Compare commits

...

381 Commits
4.7.0 ... 4.7.2

Author SHA1 Message Date
James Cole
37b02e3d5b Merge branch 'release/4.7.2' 2018-04-01 11:46:41 +02:00
James Cole
093bdd6090 Fix some last minute issues. 2018-04-01 08:50:23 +02:00
James Cole
52656b25da Let's cancel these tests for now. 2018-04-01 08:04:19 +02:00
James Cole
1386c9d915 Disable some tests. 2018-04-01 07:40:30 +02:00
James Cole
02c9441727 Last minute language updates. 2018-04-01 07:24:18 +02:00
James Cole
b1e926f2cb Use php unit 7, not 6. 2018-04-01 07:13:29 +02:00
James Cole
df9dcb395b Change composer build instructions 2018-04-01 07:02:46 +02:00
James Cole
ad59dad921 Remove deprecated features. 2018-03-31 21:42:08 +02:00
James Cole
46e75968f5 Update composer 2018-03-31 21:05:53 +02:00
James Cole
0df5c5121d Update language strings 2018-03-31 21:05:43 +02:00
James Cole
16f04b45ac Update composer file. 2018-03-31 21:05:17 +02:00
James Cole
5ce35a50c2 Make sure tests work. 2018-03-31 21:05:06 +02:00
James Cole
7110c1178a Fix bad parse error. 2018-03-30 22:49:46 +02:00
James Cole
220f5e2913 Add support for Italian. 2018-03-30 22:48:00 +02:00
James Cole
9f8c75efc6 Fix null pointer in account format. 2018-03-30 22:44:37 +02:00
James Cole
8f3e84df4d Fix possible null pointer. 2018-03-30 22:40:20 +02:00
James Cole
08ff3d8ad0 Implement test of import command. 2018-03-30 19:41:16 +02:00
James Cole
5c4d7734ac Expand test code for create export routine. 2018-03-30 16:44:33 +02:00
James Cole
15f8cd49d3 Log file security. 2018-03-30 14:50:44 +02:00
James Cole
62b3986fcd Update env files for #1280 2018-03-30 07:00:20 +02:00
James Cole
55b6d711f3 Currency exchange rate will not be saved when rate is 0. 2018-03-30 06:33:04 +02:00
James Cole
7e51d57d21 Update composer file. 2018-03-29 19:01:59 +02:00
James Cole
170d23d768 Code cleanup before release. 2018-03-29 19:01:47 +02:00
James Cole
40266c6821 Add support for Italian and update language files. 2018-03-29 19:00:21 +02:00
James Cole
0a71077513 Push updated tests. 2018-03-28 19:38:20 +02:00
James Cole
be5c44af61 Update some code, add security txt file. 2018-03-28 19:37:59 +02:00
James Cole
720dcb0fe5 Fix #1300 2018-03-27 19:29:58 +02:00
James Cole
c86b207b1c Fix #1297 2018-03-26 20:48:47 +02:00
James Cole
413c1bc2fe Fix #1294 2018-03-26 19:19:11 +02:00
James Cole
5ca31ea3dd Fix #1296 2018-03-26 19:09:58 +02:00
James Cole
dd5d2d1616 Consistent overview for #1292 2018-03-25 21:16:46 +02:00
James Cole
5f08790f12 Restore chart #1292 2018-03-25 20:52:21 +02:00
James Cole
d5ef5ee5a7 Fix #1293 2018-03-25 20:42:56 +02:00
James Cole
f641c70172 Fix #1292 2018-03-25 18:26:35 +02:00
James Cole
992657b942 Code for #1257 2018-03-25 13:30:55 +02:00
James Cole
41e468b507 Fix #1247 2018-03-25 10:17:07 +02:00
James Cole
6660306ac4 Various code cleanup. 2018-03-25 09:01:43 +02:00
James Cole
dd9694890a Code for #1291 2018-03-25 09:00:45 +02:00
James Cole
0b8654d865 Fix #1252 2018-03-25 07:59:06 +02:00
James Cole
f07dc7bd81 Finalize bunq import #1248 2018-03-25 07:55:31 +02:00
James Cole
6a6482dc7f Finish up bunq import routine. 2018-03-24 18:55:02 +01:00
James Cole
3c9b7c07af Move import to factory #1222 2018-03-24 14:05:29 +01:00
James Cole
796ab4bf2c Fixed some small issues in import routine. 2018-03-24 11:49:26 +01:00
James Cole
55602d632d Clean up code for import routine. 2018-03-24 10:35:42 +01:00
James Cole
310ed9f504 Add budget warnings #1202 2018-03-24 06:46:37 +01:00
James Cole
dafddfa39a Fix all tests. 2018-03-24 06:08:50 +01:00
James Cole
3e22c9860e Fix some tests. 2018-03-23 05:31:45 +01:00
James Cole
fb0a0c3fb5 Fix a few tests. 2018-03-23 05:31:30 +01:00
James Cole
3b735c7533 Expand views and files to use new methods. 2018-03-19 19:39:26 +01:00
James Cole
1645490f5c Avoid using model methods and use repository instead 2018-03-19 19:39:02 +01:00
James Cole
aecffe10d9 Import routine can handle new SEPA fields and many new date fields. See #1248 2018-03-19 19:38:17 +01:00
James Cole
4e69bc0e32 Add reference to FAQ [skip ci] 2018-03-19 15:44:08 +01:00
James Cole
909f72e6be Move notes for attachments to different object. This sacrifices the original notes. 2018-03-19 15:28:35 +01:00
James Cole
6a1d39d5f8 Add newlines and strict type declarations. 2018-03-19 13:23:26 +01:00
James Cole
c5d4ec17c3 Move strict type declaration. 2018-03-19 13:22:08 +01:00
James Cole
ed33a72945 Make sure that strict_types declaration is always at the very top of the file. 2018-03-19 12:09:12 +01:00
James Cole
d8c0091680 Make sure that strict_types declaration is always at the very top of the file. 2018-03-19 12:08:50 +01:00
James Cole
6419d68626 Add newlines to end of file. 2018-03-19 12:08:22 +01:00
James Cole
e2ecaf5bcf Include BIC in import routine 2018-03-19 10:03:08 +01:00
James Cole
31146954d1 Fix #1258 2018-03-19 09:33:48 +01:00
James Cole
601ca9ec80 Update German translations [skip ci] 2018-03-19 09:09:47 +01:00
James Cole
082b5ba895 Fix #1262 2018-03-19 09:09:02 +01:00
James Cole
e06361d5d7 Push strict declaration to top. 2018-03-19 08:17:42 +01:00
James Cole
552a8e130c Add support methods. 2018-03-19 08:17:31 +01:00
James Cole
40787bc29a Improve bunq import. 2018-03-19 08:17:15 +01:00
James Cole
6ab03bb228 Improve IBAN uniqueness. 2018-03-19 08:16:54 +01:00
James Cole
3fdb782321 Fix various tests. 2018-03-11 21:19:35 +01:00
James Cole
c8f52a1c40 Code cleanup [skip ci] 2018-03-11 20:41:03 +01:00
James Cole
eb63090387 Fix custom range thing for accounts #1240 [skip ci] 2018-03-11 19:01:19 +01:00
James Cole
5bc8f31c31 Add verify routine to installer. 2018-03-11 18:47:26 +01:00
James Cole
5776de7745 Update various tests. 2018-03-11 18:46:41 +01:00
James Cole
f45d0bb317 Expand install routine. 2018-03-11 18:46:18 +01:00
James Cole
93aa5b7753 Fix null pointer in chart JS [skip ci] 2018-03-11 18:40:08 +01:00
James Cole
dd6a6a565f Fix null pointer in budget report [skip ci] 2018-03-11 18:38:35 +01:00
James Cole
aba8025645 Move docker files, include kubernetes files. 2018-03-11 18:27:30 +01:00
James Cole
b12872e5de Various code cleanup. 2018-03-11 16:24:07 +01:00
James Cole
5a7b1ba292 Remove unused methods. 2018-03-11 15:55:36 +01:00
James Cole
24715c72a2 Remove unused functions. 2018-03-11 15:54:33 +01:00
James Cole
ed3a4e4663 View extension for amounts [skip ci] 2018-03-11 14:19:28 +01:00
James Cole
e97283b34b Make sure transfers can't get a budget. 2018-03-11 14:13:23 +01:00
James Cole
c2dfbcba10 Improve view for transactions. 2018-03-11 14:09:44 +01:00
James Cole
a9870b35be Remove some stuff, mark as deprecated. 2018-03-11 13:34:16 +01:00
James Cole
ed5cd2b9ca Add currency symbol. 2018-03-11 13:31:22 +01:00
James Cole
a9356ca1e2 Mark methods as deprecated. 2018-03-11 13:30:58 +01:00
James Cole
cfba11e9ca Code for #1244 2018-03-11 13:26:11 +01:00
James Cole
4304a3c916 Code for #1214 2018-03-11 13:22:34 +01:00
James Cole
9e6194bfdc Catch null pointer [skip ci] 2018-03-11 08:23:47 +01:00
James Cole
7d6c8aa9dc Fix null pointer. 2018-03-11 08:22:20 +01:00
James Cole
aad0864018 Various code cleanup [skip ci] 2018-03-10 22:38:20 +01:00
James Cole
a55d18709c More code to catch exceptions in #1238 2018-03-10 22:34:02 +01:00
James Cole
dd2f3c861b Optimize imports. 2018-03-10 20:30:09 +01:00
James Cole
da1dc67e1c Validation message. 2018-03-10 20:25:55 +01:00
James Cole
0c2b35e542 Improve bunq import. 2018-03-10 20:25:42 +01:00
James Cole
85dc1263ea Fix #1238 2018-03-10 20:25:11 +01:00
James Cole
c8ecb3e0ee Fix #1199 for web interface 2018-03-10 09:44:04 +01:00
James Cole
ce10036a27 Fix #1199 in API 2018-03-10 09:39:49 +01:00
James Cole
30e49846e0 First list existing devices, then try to get a new one. 2018-03-10 07:33:49 +01:00
James Cole
be97dd1c57 Expand various views. 2018-03-10 07:17:23 +01:00
James Cole
648a6dca42 Expand install routine. 2018-03-10 07:17:05 +01:00
James Cole
0566d0d198 Expand bunq import. 2018-03-10 07:16:38 +01:00
James Cole
dfc25722c9 Expand debug page with locale information. 2018-03-10 07:15:21 +01:00
James Cole
a436c55c50 Code for #1236 2018-03-10 06:49:03 +01:00
James Cole
0d58530f55 Fix #1237 2018-03-09 20:58:46 +01:00
James Cole
04b2eaf535 Fix tests that broke during Laravel 5.6 upgrade 2018-03-09 06:46:45 +01:00
James Cole
ace2ed8bd0 Fix #1213 2018-03-09 05:52:52 +01:00
James Cole
dff2d716a1 Move 2FA to profile #1153 2018-03-09 05:45:22 +01:00
James Cole
ad18b9b81b Remove optional chart (always enabled) 2018-03-09 05:44:35 +01:00
James Cole
eabfe0769b Update explanation for new PW hash check. 2018-03-09 04:48:17 +01:00
James Cole
19f7027718 Fix #1198 2018-03-09 04:47:43 +01:00
James Cole
f537945351 Fix #1236 2018-03-09 04:04:42 +01:00
James Cole
d02372ab90 Fix debug controller for Laravel 5.6 2018-03-08 21:08:26 +01:00
James Cole
1b020c522f Fix currency test. 2018-03-08 21:02:46 +01:00
James Cole
79d0450c77 Implement new password verifier #1187 2018-03-08 20:44:56 +01:00
James Cole
bc32bc8831 Stop Travis from optimising. 2018-03-08 06:13:06 +01:00
James Cole
f68a307eeb Fix file names, ignore installer in test env 2018-03-07 21:04:10 +01:00
James Cole
82e7479cfe Force fresh config var [skip ci] 2018-03-07 21:01:46 +01:00
James Cole
462fe5d89f Force migration [skip ci]Middleware log. [skip ci] 2018-03-07 20:59:32 +01:00
James Cole
b0d8ac83ae Middleware log. [skip ci] 2018-03-07 20:58:54 +01:00
James Cole
d8ac817c91 Middleware log. [skip ci] 2018-03-07 20:56:52 +01:00
James Cole
5105bc6f64 Add more debug logging to output. 2018-03-07 20:55:11 +01:00
James Cole
47c9f1e9b8 Update logging for Laravel 5.6 #1221 2018-03-07 20:47:39 +01:00
James Cole
49d0ed0c1b Fix null pointer. 2018-03-07 20:41:17 +01:00
James Cole
99f5151aab Remove coverage for methods that do not exist. 2018-03-07 20:39:33 +01:00
James Cole
0a056ad02d Upgrade to Laravel 5.6 #1221 2018-03-07 20:37:00 +01:00
James Cole
c76b634d0b Fix #1189 2018-03-07 20:27:10 +01:00
James Cole
a81698d50f Code for #1219 2018-03-07 20:25:58 +01:00
James Cole
bae79063e1 Code to fix #1234 2018-03-07 20:21:51 +01:00
James Cole
fb5323c283 Code to facilitate #1123 2018-03-07 20:21:36 +01:00
James Cole
e2d1de94b7 Fix tests to catch use of repositories 2018-03-07 10:18:50 +01:00
James Cole
7109fd8196 Correct reference to journal description 2018-03-07 10:18:36 +01:00
James Cole
a5fd821e0c Code to implement #1168 and #1197. 2018-03-07 10:18:22 +01:00
James Cole
6c63583e49 Fix test to always select correct journal. 2018-03-07 05:52:45 +01:00
James Cole
dd16e1b784 Expand list of bills for #1102 2018-03-07 05:52:34 +01:00
James Cole
d52d8d7970 Expand exception code and fix demo user redirect. 2018-03-07 05:51:51 +01:00
James Cole
f349aa47ce Merge pull request #1232 from benyanke/patch-1
Allow user to specify port
2018-03-06 05:22:46 +01:00
James Cole
ef4018934c Merge branch 'release/4.7.1.4' 2018-03-06 05:15:04 +01:00
Ben Yanke
951aa9535e Allow user to specify port 2018-03-05 20:49:21 -06:00
James Cole
de1fe36226 Fix #1226 2018-03-05 19:56:50 +01:00
James Cole
64fd36d437 Fix #1227 2018-03-05 19:39:41 +01:00
James Cole
6f9ecc0ffa Update version. [skip ci] 2018-03-05 19:37:06 +01:00
James Cole
a97bfc92e1 Add newlines and strict types 2018-03-05 19:35:58 +01:00
James Cole
0d72fcdf02 Fix #1225 2018-03-05 19:35:39 +01:00
James Cole
0e84ca1df5 Merge branch 'release/4.7.1.3' 2018-03-04 20:57:12 +01:00
James Cole
b28bdda510 Move base href to top of page. 2018-03-04 20:40:49 +01:00
James Cole
72314e2d9f Expand tests for updated triggers / actions. 2018-03-04 17:10:36 +01:00
James Cole
d22fb9f438 Improve tests for transaction rules. 2018-03-04 16:42:29 +01:00
James Cole
04b8552d27 Implement tests. 2018-03-04 16:30:20 +01:00
James Cole
5d6f44cd91 Fix test that could select a deposit or transfer. 2018-03-04 16:07:03 +01:00
James Cole
afc8ad7ff5 Clean test. 2018-03-04 15:57:19 +01:00
James Cole
ae039bf1c7 Update composer file for failed passport thing and update version. 2018-03-04 15:36:06 +01:00
James Cole
8fa25e9d37 Update read me file. 2018-03-04 15:25:43 +01:00
James Cole
0daab491ec Remove unused file [skip ci] 2018-03-04 15:16:37 +01:00
James Cole
4f825bac1a Add newlines to files [skip ci] 2018-03-04 15:16:18 +01:00
James Cole
39c8b79ebb Add newlines to files [skip ci] 2018-03-04 15:14:29 +01:00
James Cole
7d66c90beb Make sure that the API returns all entries of a split transaction. 2018-03-04 14:20:23 +01:00
James Cole
1b8b65582a Merge branch 'release/4.7.1.2' 2018-03-04 13:27:21 +01:00
James Cole
d25971cb44 Actually upgrade version. 2018-03-04 13:26:35 +01:00
James Cole
89a56e661d Merge branch 'hotfix/4.7.1.1' into develop 2018-03-04 13:24:07 +01:00
James Cole
3482746d7c Merge branch 'hotfix/4.7.1.1' 2018-03-04 13:24:06 +01:00
James Cole
d5aeca6222 Fix import problem in 4.7.1 2018-03-04 13:23:44 +01:00
James Cole
03f46638e1 Merge branch 'release/4.7.1' 2018-03-04 10:52:17 +01:00
James Cole
c2b000d910 Update change log. 2018-03-04 10:39:40 +01:00
James Cole
88eb702d7b Update Sandstorm files. 2018-03-04 10:39:31 +01:00
James Cole
b1d98f026f Update docker file. 2018-03-04 10:39:00 +01:00
James Cole
28dfe7b02c Update test config. 2018-03-04 10:38:50 +01:00
James Cole
84f0ee183c Fix tests. 2018-03-04 09:49:15 +01:00
James Cole
7eedd6c2fc Update changelog and increment version. 2018-03-04 09:13:15 +01:00
James Cole
e7b80c6d10 Fix parameter error in test script. 2018-03-04 09:12:58 +01:00
James Cole
d165609476 Expand debug view with API version. 2018-03-04 09:12:47 +01:00
James Cole
2f17521c06 Fix small errors in bulk and mass controller 2018-03-04 09:12:33 +01:00
James Cole
8b52006959 Updated all language strings. 2018-03-04 08:54:01 +01:00
James Cole
8eb3d43123 Fix tag auto select. 2018-03-04 08:52:06 +01:00
James Cole
a511368229 Fix missing index. 2018-03-04 08:51:46 +01:00
James Cole
f0006a0743 Update composer lock file. 2018-03-04 08:51:20 +01:00
James Cole
7171e69715 All API routes seem to work. 2018-03-04 08:22:32 +01:00
James Cole
2ab44fb33a Improve test coverage. 2018-03-04 07:56:30 +01:00
James Cole
7542175258 Improve test coverage. 2018-03-03 17:16:47 +01:00
James Cole
9dc4c50527 Expand test coverage. 2018-03-03 14:24:06 +01:00
James Cole
99d116f4ce Improve test coverage. 2018-03-03 10:15:39 +01:00
James Cole
9475fef8f6 Implement user API and first tests. 2018-03-03 08:12:18 +01:00
James Cole
60339a0f6a make sure randomly selected journals match prerequisites. 2018-03-02 17:29:47 +01:00
James Cole
36113f84be make sure randomly selected journals match prerequisites. 2018-03-02 17:07:32 +01:00
James Cole
139c2284b8 Various code cleanup. 2018-03-02 16:31:02 +01:00
James Cole
91909a70d7 Fix #1209 2018-03-02 03:14:36 +01:00
James Cole
a23d97563f Fix tests that selected split journals. 2018-03-01 21:39:31 +01:00
James Cole
bf538e2514 Merge pull request #1211 from m0nhawk/patch-1
3 new european currencies in database seed
2018-03-01 21:28:36 +01:00
Andrew Prokhorenkov
149b62f486 3 new european currencies in database seed 2018-03-01 22:20:04 +02:00
James Cole
06dc8a499b Expand factory tests. 2018-03-01 20:54:50 +01:00
James Cole
5b8479f3a4 Remove PHP 7.2 support. 2018-03-01 17:40:06 +01:00
James Cole
e803a5e26e Fix test coverage. 2018-03-01 17:20:06 +01:00
James Cole
959f798a7f Update English strings. 2018-02-28 21:33:14 +01:00
James Cole
5b8adbfd0c Repository and test clean up. 2018-02-28 21:32:59 +01:00
James Cole
54ba18975a Use different method for finding objects. 2018-02-28 20:23:45 +01:00
James Cole
fdd2dedfc6 Fix test cases. 2018-02-28 20:18:47 +01:00
James Cole
46f4fa1a7d Expand tests. 2018-02-28 15:50:00 +01:00
James Cole
28debb46be Needs to return bill to work. 2018-02-28 14:57:58 +01:00
James Cole
5f132be94d Add catalan (still in comments, because its incomplete [skip ci] 2018-02-28 07:22:57 +01:00
James Cole
9f9feea159 Code to fix #1185 2018-02-28 07:22:11 +01:00
James Cole
3bd9e0bcd4 Remove not existing method 2018-02-27 07:39:28 +01:00
James Cole
c80a76f8c0 Remove not existing method. 2018-02-27 07:37:40 +01:00
James Cole
c71f498587 Merge branches 'develop' and 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Update validation.php
  Update config.php

* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Update validation.php
  Update config.php
2018-02-26 21:09:51 +01:00
James Cole
e658d447ca Update validation. 2018-02-26 21:09:33 +01:00
James Cole
33def5b45d Update validation.php 2018-02-26 13:18:34 +01:00
James Cole
9fc26a8ee0 Update config.php 2018-02-26 13:15:54 +01:00
James Cole
1b304bf85e use journal repository instead of direct calls. 2018-02-25 19:09:05 +01:00
James Cole
99983a5c8f Match default values #1191 2018-02-25 17:39:19 +01:00
James Cole
d01b370cd7 Change docker vars #1191 2018-02-25 17:39:09 +01:00
James Cole
1a643e2042 Expand tests 2018-02-25 17:38:24 +01:00
James Cole
1aaf5fd288 Improve split controller code. 2018-02-25 16:04:25 +01:00
James Cole
8a758b8df0 Fix #1192 2018-02-25 15:09:57 +01:00
James Cole
211caa07dc Update edit and submit routines for transactions. 2018-02-24 14:31:20 +01:00
James Cole
ac66e89edb Expand some tests. 2018-02-24 09:18:01 +01:00
James Cole
6fe5b50410 Expand view + JS for view to cope with new factory 2018-02-24 09:17:48 +01:00
James Cole
166cdad58b Some intermittent changes to storing journals. 2018-02-24 09:17:15 +01:00
James Cole
1a721ac6b5 Fix transactions. 2018-02-23 16:59:21 +01:00
James Cole
6591fa9fb4 Small adjustments to fix tests. 2018-02-23 16:21:28 +01:00
James Cole
d804093f8b Expand destroy routine. 2018-02-23 15:13:30 +01:00
James Cole
5261b784b0 New validation 2018-02-23 15:13:23 +01:00
James Cole
5a188ceca3 Remove triggers 2018-02-23 15:13:16 +01:00
James Cole
ce56cc538d Remove bad method. 2018-02-23 15:13:09 +01:00
James Cole
269433bf00 Refactor reconciliation routine 2018-02-23 15:13:01 +01:00
James Cole
dae3371c69 Move common methods to traits 2018-02-23 15:12:47 +01:00
James Cole
38c1d332e2 Removed a lot of old spaghetti code. Now have to rewrite it 2018-02-22 20:13:00 +01:00
James Cole
b627d42160 Code removal. The code removed from these classes must move to respective services. 2018-02-22 20:07:14 +01:00
James Cole
4e923057ae Clean up repository. 2018-02-21 21:11:44 +01:00
James Cole
35d0bd1985 Factory seems to work for update and create 2018-02-21 21:06:59 +01:00
James Cole
085eb650e7 Code cleanup. 2018-02-21 20:34:48 +01:00
James Cole
b4157e8ce0 Build account update service. 2018-02-21 20:34:24 +01:00
James Cole
81221038f0 Expand services. 2018-02-21 18:42:15 +01:00
James Cole
9f37bf5875 Fix budget controller tests. 2018-02-21 09:23:20 +01:00
James Cole
140a5b20db Update transactions, delete splits. 2018-02-21 08:58:06 +01:00
James Cole
e9b6b45fc4 Expand code to be able to handle updates. 2018-02-21 08:51:30 +01:00
James Cole
f16760d607 Expand API validation. 2018-02-20 18:03:02 +01:00
James Cole
9d457787f7 Specify times for SQLite database. #1192 2018-02-20 17:17:14 +01:00
James Cole
4e6afd5afc Remove todo items [skip ci] 2018-02-19 20:32:44 +01:00
James Cole
36354c3846 Fix for #1111 2018-02-19 20:32:33 +01:00
James Cole
9f63dfb9cb Fix #1178 [skip ci] 2018-02-19 20:17:37 +01:00
James Cole
cae4faad0a Expand tests. 2018-02-19 20:02:27 +01:00
James Cole
e389d0f7fa Expand tests 2018-02-19 19:45:13 +01:00
James Cole
6b32213735 make findByName nullable. 2018-02-19 19:44:58 +01:00
James Cole
b3fe24b713 Expand and refactor factories. 2018-02-19 19:44:46 +01:00
James Cole
5bb7530642 Expand tests. 2018-02-18 20:40:32 +01:00
James Cole
0b61c16eb0 Expand test cases for transaction creation through the API. 2018-02-18 19:55:35 +01:00
James Cole
77aced6734 Test every happy path for journal creation. 2018-02-18 16:35:26 +01:00
James Cole
94a7b6b9bd First create basic objects. Then, enhance. 2018-02-18 10:52:56 +01:00
James Cole
f8bf6c163f Add some factory stuff before another refactoring. 2018-02-18 10:49:42 +01:00
James Cole
eb0da038fb Expand tests and API code. 2018-02-18 10:31:15 +01:00
James Cole
6cda9f2900 Expand tests for account API. 2018-02-17 19:56:45 +01:00
James Cole
ecd4a862ff Tests for API controllers 2018-02-17 14:46:12 +01:00
James Cole
632d50a0d0 Fix all tests. 2018-02-17 14:14:26 +01:00
James Cole
0f1cc46b71 Fix JSON tests 2018-02-17 12:33:42 +01:00
James Cole
60b225d61c Fix use of transformer. 2018-02-17 12:24:29 +01:00
James Cole
23e540a57a Fix missing methods in account controller test 2018-02-17 10:50:47 +01:00
James Cole
1998412a3c Remove API tests for the time being. 2018-02-17 10:48:31 +01:00
James Cole
7bbfb692de Move code to repository. 2018-02-17 10:47:32 +01:00
James Cole
c6da990748 Expand decryption routine. 2018-02-17 10:47:18 +01:00
James Cole
049e57d578 New tests for object transformers. 2018-02-17 10:47:06 +01:00
James Cole
78ba0f749c tests for bill and attachment transformers. 2018-02-16 22:47:08 +01:00
James Cole
9cc1bfb4b5 Improve code for test coverage 2018-02-16 22:14:53 +01:00
James Cole
278b7ac52b First tests for transformers. 2018-02-16 22:14:34 +01:00
James Cole
645a29e22b Add API test suite 2018-02-16 22:14:08 +01:00
James Cole
b22d30bc65 Add method to mark journals as completed. 2018-02-16 16:58:08 +01:00
James Cole
2ee0490141 Remove debug info. 2018-02-16 16:57:54 +01:00
James Cole
1fd783de69 Remove debug info. 2018-02-16 16:57:46 +01:00
James Cole
8073896965 Add request data for tags. 2018-02-16 16:57:35 +01:00
James Cole
8a26e43c40 Fix display for new transaction store. 2018-02-16 16:57:27 +01:00
James Cole
a302aba3ab Expand journal repos 2018-02-16 16:45:03 +01:00
James Cole
0458058cb1 Update piggy bank transformer 2018-02-16 16:44:52 +01:00
James Cole
999bb5ed49 Add new transaction type repository 2018-02-16 16:44:21 +01:00
James Cole
c9f4a1eb7b Add route binder to transaction 2018-02-16 16:43:57 +01:00
James Cole
45aa76afce Expand collector to return single journals. 2018-02-16 16:43:48 +01:00
James Cole
e89a77efb1 New factories for the creation of journals and associated meta data. 2018-02-16 16:43:25 +01:00
James Cole
8f930d6dd5 Transaction request with full validation 2018-02-16 16:43:00 +01:00
James Cole
9d62b4c70d Add return types 2018-02-16 16:42:23 +01:00
James Cole
834032f58e Updated transaction controller 2018-02-16 16:42:13 +01:00
James Cole
33db99ffd3 Update find methods to return null 2018-02-16 15:19:19 +01:00
James Cole
28b00f6507 New routes for transaction 2018-02-16 15:18:07 +01:00
James Cole
6559076c48 New strings for validation 2018-02-16 15:17:55 +01:00
James Cole
60f6311e00 Rule to validate if object belongs to submitting user. 2018-02-16 15:17:36 +01:00
James Cole
574a5630e0 Add binder for transactions 2018-02-16 14:52:16 +01:00
James Cole
d3294be1bc Add method that makes sure that URL's are expanded for page navigation/ 2018-02-16 14:51:59 +01:00
James Cole
22fdc81de2 Refactor transactions. 2018-02-13 21:04:15 +01:00
James Cole
370e9b25d1 Expand API. 2018-02-13 18:24:06 +01:00
James Cole
30f821af3e About controller for basic site info 2018-02-13 18:23:26 +01:00
James Cole
7a5aa1c39b Update and restructure YAML file for Docker. [skip ci] 2018-02-11 20:53:30 +01:00
James Cole
f674df4422 Fix empty title. 2018-02-11 20:45:48 +01:00
James Cole
c2da5931ec Expanded API code, wrote a bunch new transformers as well. 2018-02-11 20:45:33 +01:00
James Cole
94f6bd34c7 Fix some issues with semi-colon delimiters, see #1172 2018-02-11 15:52:24 +01:00
James Cole
e066a6421c Fix #1172 2018-02-11 15:36:16 +01:00
James Cole
ef338e2515 Fix #1174 2018-02-11 15:27:28 +01:00
James Cole
dcf549261c Fix for #1175 2018-02-11 15:24:19 +01:00
James Cole
8b868b426a First API routes for accounts. 2018-02-11 08:08:08 +01:00
James Cole
2ef1022c92 Make sure bills API is consistent. 2018-02-11 07:46:34 +01:00
James Cole
9b3abd3b19 Expand transformers to include other objects. 2018-02-10 10:58:06 +01:00
James Cole
db02fefcf4 Update composer. 2018-02-10 09:58:06 +01:00
James Cole
523ae83811 Show proper 404 page for JSON. 2018-02-10 09:57:56 +01:00
James Cole
4eb010f807 Use correct CSS in 404 page. 2018-02-10 09:57:47 +01:00
James Cole
4958f28052 Allow API to work with bills. 2018-02-10 09:57:31 +01:00
James Cole
7e727b63ed Use built-in PHPUnit in tests. 2018-02-10 09:57:05 +01:00
James Cole
138c38fbb5 Clean up code in validator. 2018-02-10 09:22:13 +01:00
James Cole
2e61bb7375 Fix tests. 2018-02-10 09:22:04 +01:00
James Cole
fce4c9174d Fix for #1154 2018-02-10 08:21:35 +01:00
James Cole
2220963899 Remove guard from user model. 2018-02-10 08:21:20 +01:00
James Cole
e69e6c1ce8 Would be nice to remove the references as well... 2018-02-09 19:28:16 +01:00
James Cole
0f09a9db4d Remove reference to guard from other bind support classes. 2018-02-09 19:24:30 +01:00
James Cole
53a6c10ada Remove reference to guard from models. 2018-02-09 19:24:15 +01:00
James Cole
14772469ed Remove reference to guard from binder 2018-02-09 19:23:31 +01:00
James Cole
55f13ef121 Code cleanup in 2FA middleware. 2018-02-09 19:12:46 +01:00
James Cole
95648c37b3 Various code cleanup. 2018-02-09 19:11:55 +01:00
James Cole
ac98822a55 Fix for issue #1167 2018-02-09 16:47:01 +01:00
James Cole
c460419166 Final fixes for API binder. 2018-02-09 15:01:22 +01:00
James Cole
d2a8819dd4 Merge branch 'apifix' into develop
* apifix:
  Fix issues with API authentication.

# Conflicts:
#	app/Api/V1/Controllers/BillController.php
#	app/Http/Middleware/HttpBinder.php
#	app/Transformers/AttachmentTransformer.php
#	app/Transformers/BillTransformer.php
#	app/Transformers/NoteTransformer.php
#	routes/api.php
2018-02-09 14:57:39 +01:00
James Cole
d393c693de Fix issues with API authentication. 2018-02-09 14:47:37 +01:00
James Cole
d4a84ed198 Update tests. 2018-02-07 16:49:11 +01:00
James Cole
e8c7986a58 Rename binder test 2018-02-07 16:20:40 +01:00
James Cole
809e40c5ce Remove double middleware from routes. 2018-02-07 11:20:37 +01:00
James Cole
f445a95c26 Consistent use of links in transformers. 2018-02-07 11:20:24 +01:00
James Cole
909dc212fb make sure all route binders use guard. 2018-02-07 11:15:36 +01:00
James Cole
eacc1da157 Implement multi purpose binder 2018-02-07 11:13:04 +01:00
James Cole
587ad1298d Make sure transformer accepts null dates. 2018-02-07 10:49:24 +01:00
James Cole
fae7dabbc2 Split binder in api and http binder 2018-02-07 10:49:06 +01:00
James Cole
3a813c30b4 Clean up js file. 2018-02-06 19:52:46 +01:00
James Cole
3de46f55fa Use transformer in view. 2018-02-06 19:49:53 +01:00
James Cole
3aa922341c Remove unused package from config 2018-02-06 19:49:38 +01:00
James Cole
e94043edc2 Expand transformers. 2018-02-06 19:49:29 +01:00
James Cole
da91645ec0 Clean up code. 2018-02-06 19:49:16 +01:00
James Cole
178072d3af Remove unused markdown method 2018-02-06 19:49:09 +01:00
James Cole
811d8e330f Refer to correct location for bill transformer. 2018-02-06 19:48:56 +01:00
James Cole
d3c8d06114 Update lock files 2018-02-06 19:48:43 +01:00
James Cole
82dc0045ba Move bill transformer to previous location 2018-02-06 19:48:32 +01:00
James Cole
3d06f0ac14 Remove unused dependencies 2018-02-06 18:15:26 +01:00
James Cole
b5c0ef01d9 Clean up app.js 2018-02-06 18:13:54 +01:00
James Cole
3a5d3016c7 Refer to correct bill route 2018-02-06 18:12:43 +01:00
James Cole
20690b4d5b Clean up API routes 2018-02-06 18:12:31 +01:00
James Cole
2816a4a325 Make bill views use transformer object. 2018-02-06 18:12:09 +01:00
James Cole
2f4f37778c Fix error page CSS 2018-02-06 18:11:46 +01:00
James Cole
c4507a7f75 Make sure the "classic" page uses the transformer as well. 2018-02-06 18:11:33 +01:00
James Cole
9a0672e359 Update previous view to use new strings. 2018-02-06 10:57:23 +01:00
James Cole
f128db35c6 Update view to use localized strings. 2018-02-06 10:57:07 +01:00
James Cole
a2cfaa0867 Update language strings. 2018-02-06 10:56:50 +01:00
James Cole
5850c5e20a Add code to enable localisation. 2018-02-06 10:56:37 +01:00
James Cole
e77a1e403f Expand config for localisation 2018-02-06 10:56:17 +01:00
James Cole
b72e8db7b1 Add localisation package. 2018-02-06 10:56:01 +01:00
James Cole
07506784f4 Add localisation package. 2018-02-06 10:55:40 +01:00
James Cole
0435e42b3d Update package files. 2018-02-06 07:52:04 +01:00
James Cole
31884bbba6 Add generated js / css to all views. 2018-02-06 07:51:49 +01:00
James Cole
6b38faf84e Expand views for bills. 2018-02-06 07:51:28 +01:00
James Cole
2f95f99890 Update exceptions thrown for better IDE support. 2018-02-06 07:50:19 +01:00
James Cole
9b78069f41 Expand API for bills. 2018-02-06 07:49:56 +01:00
James Cole
559c2042ac Remove library now included in npm build. 2018-02-06 07:49:19 +01:00
James Cole
ae3b369e9a Match layout to Firefly III 2018-02-04 15:58:03 +01:00
James Cole
31a6565e17 Add package fractal. 2018-02-04 15:57:48 +01:00
James Cole
f488bbde02 First basic routes and code for bills. 2018-02-04 15:57:35 +01:00
James Cole
e668b88fb5 Make sure authorise view is translatable and matches Firefly III 2018-02-04 14:04:52 +01:00
James Cole
2d0aa4af96 Give all web routes full namespace. 2018-02-04 14:04:29 +01:00
James Cole
6e67416c83 Blank namespace for route namespace prefix. 2018-02-04 13:55:36 +01:00
James Cole
1ef28cbc02 Changes to repair API auth 2018-02-04 13:41:59 +01:00
James Cole
58bdf14f6b First empty controllers for API. 2018-02-04 13:41:42 +01:00
James Cole
9f4ecb0963 Make authorise view a twig file. 2018-02-04 11:21:57 +01:00
James Cole
b1259a014f Add support for Spanish [skip ci] 2018-02-04 09:52:42 +01:00
James Cole
142d0b5af2 First set of JS/CSS built by npm. 2018-02-04 09:23:46 +01:00
James Cole
450e2bad1c New composer.lock after installing Laravel Passport. 2018-02-04 09:23:20 +01:00
James Cole
089300d57e Update date related code to fix several issues with SQLite 2018-02-04 09:22:52 +01:00
James Cole
36f67793cb Include Vue components. 2018-02-04 08:17:22 +01:00
James Cole
c335a9bbc8 Rename access token variables 2018-02-04 08:17:05 +01:00
James Cole
029688a594 Passport auth view. 2018-02-04 08:16:37 +01:00
James Cole
6f2eb33fd0 Future strings for JS translations 2018-02-04 08:16:06 +01:00
James Cole
8351020913 Add passport components to app.js 2018-02-04 08:15:20 +01:00
James Cole
220efca8d7 Add passport migrations 2018-02-04 08:14:36 +01:00
James Cole
28579f7b80 Add debug information to import routine. 2018-02-04 08:14:22 +01:00
James Cole
f1d77bdb50 Expand code to support laravel passport 2018-02-04 08:14:03 +01:00
James Cole
ca8b4cb11a Add laravel passport 2018-02-04 08:13:31 +01:00
James Cole
31dbb7b111 Update view to use new assets 2018-02-03 09:14:58 +01:00
James Cole
352cdf75c8 Include font awesome in assets. 2018-02-03 09:14:39 +01:00
James Cole
d81c99bcda Other name for CSRF token in html and JS. 2018-02-01 19:39:55 +01:00
James Cole
1e2c979341 Fix #1155 2018-02-01 19:39:41 +01:00
James Cole
d8664096f9 Fix view issues when user has multiple pages of budgets #1111 2018-02-01 17:55:18 +01:00
James Cole
0d9a221b00 Extend debug page with session fields. 2018-02-01 16:58:47 +01:00
James Cole
de85f17cac Improve login form autocomplete values [skip ci] 2018-02-01 16:54:42 +01:00
James Cole
e3d6f4f00f Add some Vue related components. Prep for inclusion of passport and other tools. 2018-01-31 17:55:49 +01:00
James Cole
d0e0054b00 Correct errors in English sentences. [skip ci] 2018-01-31 14:02:04 +01:00
858 changed files with 58663 additions and 17561 deletions

View File

@@ -0,0 +1,82 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-export-claim
labels:
app: firefly-local
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-upload-claim
labels:
app: firefly-local
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: firefly-local
namespace: firefly
labels:
app: firefly-local
spec:
selector:
matchLabels:
app: firefly-local
template:
metadata:
labels:
app: firefly-local
spec:
containers:
- image: firefly-local
name: firefly-local
env:
- name: FF_APP_ENV
value: "local"
- name: FF_APP_KEY
value: "S0m3R@nd0mString0f32Ch@rsEx@ct1y"
- name: FF_DB_HOST
value: "172.17.0.9"
- name: FF_DB_NAME
value: "firefly_db"
- name: FF_DB_USER
value: "firefly_db"
- name: FF_DB_PASSWORD
value: "password"
volumeMounts:
- mountPath: "/var/www/firefly-iii/storage/export"
name: mysql-persistent-export
- mountPath: "/var/www/firefly-iii/storage/upload"
name: mysql-persistent-upload
imagePullPolicy: IfNotPresent
volumes:
- name: mysql-persistent-export
persistentVolumeClaim:
claimName: mysql-pv-export-claim
- name: mysql-persistent-upload
persistentVolumeClaim:
claimName: mysql-pv-upload-claim
---
apiVersion: v1
kind: Service
metadata:
name: firefly-local
spec:
ports:
- port: 80
type: NodePort
selector:
app: firefly-local

View File

@@ -0,0 +1,49 @@
apiVersion: v1
kind: Secret
metadata:
name: sql-pass
type: Opaque
data:
password: cGFzc3dvcmQ=
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mysql
namespace: firefly
labels:
app: mysql
spec:
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql
imagePullPolicy: IfNotPresent
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: sql-pass
key: password
ports:
- containerPort: 3306
name: mysql
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
type: NodePort
selector:
app: mysql

View File

@@ -3,10 +3,10 @@
APP_ENV=${FF_APP_ENV}
# Set to true if you want to see debug information in error screens.
APP_DEBUG=false
APP_DEBUG=${APP_DEBUG}
# This should be your email address
SITE_OWNER=mail@example.com
SITE_OWNER=${SITE_OWNER}
# The encryption key for your database and sessions. Keep this very secure.
# If you generate a new one all existing data must be considered LOST.
@@ -17,11 +17,14 @@ APP_KEY=${FF_APP_KEY}
APP_URL=${APP_URL}
TRUSTED_PROXIES=${TRUSTED_PROXIES}
# The log channel defines where your log entries go to.
LOG_CHANNEL=${LOG_CHANNEL}
# 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.
DB_CONNECTION=mysql
DB_HOST=${FF_DB_HOST}
DB_PORT=3306
DB_PORT=${FF_DB_PORT}
DB_DATABASE=${FF_DB_NAME}
DB_USERNAME=${FF_DB_USER}
DB_PASSWORD=${FF_DB_PASSWORD}
@@ -29,13 +32,13 @@ 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=daily
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=warning
APP_LOG_LEVEL=info
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
@@ -47,23 +50,28 @@ COOKIE_DOMAIN=
COOKIE_SECURE=false
# If you want Firefly III to mail you, update these settings
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_FROM=changeme@example.com
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_DRIVER=${MAIL_DRIVER}
MAIL_HOST=${MAIL_HOST}
MAIL_PORT=${MAIL_PORT}
MAIL_FROM=${MAIL_FROM}
MAIL_USERNAME=${MAIL_USERNAME}
MAIL_PASSWORD=${MAIL_PASSWORD}
MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=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=
MAPBOX_API_KEY=${MAPBOX_API_KEY}
# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates.
# Please note that this will only work for paid fixer.io accounts because they severly limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=${FIXER_API_KEY}
# If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here.
ANALYTICS_ID=
ANALYTICS_ID=${ANALYTICS_ID}
# Most parts of the database are encrypted by default, but you can turn this off if you want to.
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
@@ -79,7 +87,6 @@ REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_PREFIX=firefly
SEARCH_RESULT_LIMIT=50
EXCHANGE_RATE_SERVICE=fixerio
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_ID=
@@ -88,3 +95,4 @@ DEMO_PASSWORD=
IS_DOCKER=true
IS_SANDSTORM=false
IS_HEROKU=false
TZ=${TZ}

View File

@@ -13,12 +13,19 @@ SITE_OWNER=mail@example.com
# Change it to a string of exactly 32 chars or use command `php artisan key:generate` to generate it
APP_KEY=SomeRandomStringOf32CharsExactly
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=UTC
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
APP_URL=http://localhost
TRUSTED_PROXIES=
# The log channel defines where your log entries go to.
LOG_CHANNEL=daily
# 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=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
@@ -62,6 +69,11 @@ SEND_ERROR_MESSAGE=true
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
MAPBOX_API_KEY=
# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates.
# Please note that this will only work for paid fixer.io accounts because they severly limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
# If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here.
ANALYTICS_ID=
@@ -79,7 +91,6 @@ REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_PREFIX=firefly
SEARCH_RESULT_LIMIT=50
EXCHANGE_RATE_SERVICE=fixerio
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_ID=

View File

@@ -13,10 +13,17 @@ SITE_OWNER=heroku@example.com
# Change it to a string of exactly 32 chars or use command `php artisan key:generate` to generate it
APP_KEY=7ahyYVPVsmxjdhsweWCauGeJfwc92NP2
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=UTC
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
APP_URL=http://localhost
TRUSTED_PROXIES=
# The log channel defines where your log entries go to.
LOG_CHANNEL=syslog
# 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.
DB_CONNECTION=pgsql
@@ -62,6 +69,11 @@ SEND_ERROR_MESSAGE=true
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
MAPBOX_API_KEY=
# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates.
# Please note that this will only work for paid fixer.io accounts because they severly limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
# If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here.
ANALYTICS_ID=
@@ -79,7 +91,6 @@ REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_PREFIX=firefly
SEARCH_RESULT_LIMIT=50
EXCHANGE_RATE_SERVICE=fixerio
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_ID=

View File

@@ -13,10 +13,17 @@ SITE_OWNER=sandstorm@example.com
# Change it to a string of exactly 32 chars or use command `php artisan key:generate` to generate it
APP_KEY=SomeRandomStringOf32CharsExactly
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=UTC
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
APP_URL=http://localhost
TRUSTED_PROXIES=
# The log channel defines where your log entries go to.
LOG_CHANNEL=syslog
# 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.
DB_CONNECTION=mysql
@@ -62,6 +69,11 @@ SEND_ERROR_MESSAGE=true
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
MAPBOX_API_KEY=
# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates.
# Please note that this will only work for paid fixer.io accounts because they severly limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
# If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here.
ANALYTICS_ID=
@@ -79,7 +91,6 @@ REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_PREFIX=firefly
SEARCH_RESULT_LIMIT=50
EXCHANGE_RATE_SERVICE=fixerio
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_ID=

View File

@@ -1,33 +1,55 @@
# You can leave this on "local". If you change it to production most console commands will ask for extra confirmation.
# Never set it to "testing".
APP_ENV=testing
# Set to true if you want to see debug information in error screens.
APP_DEBUG=true
APP_NAME=FireflyIII
# This should be your email address
SITE_OWNER=thegrumpydictator+testing@gmail.com
# The encryption key for your database and sessions. Keep this very secure.
# If you generate a new one all existing data must be considered LOST.
# Change it to a string of exactly 32 chars or use command `php artisan key:generate` to generate it
APP_KEY=TestTestTestTestTestTestTestTest
APP_LOG=daily
APP_LOG_LEVEL=debug
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=Europe/Amsterdam
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
APP_URL=http://localhost
TRUSTED_PROXIES=
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
#DB_DATABASE=firefly
DB_USERNAME=homestead
DB_PASSWORD=
# The log channel defines where your log entries go to.
LOG_CHANNEL=dailytest
BROADCAST_DRIVER=log
# 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
# 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
QUEUE_DRIVER=sync
# Cookie settings. Should not be necessary to change these.
COOKIE_PATH="/"
COOKIE_DOMAIN=
COOKIE_SECURE=false
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
# If you want Firefly III to mail you, update these settings
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_FROM=changeme@example.com
@@ -35,26 +57,41 @@ MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
SEND_ERROR_MESSAGE=false
CACHE_PREFIX=firefly
SEARCH_RESULT_LIMIT=50
EXCHANGE_RATE_SERVICE=fixerio
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
MAPBOX_API_KEY=
ANALYTICS_ID=
SITE_OWNER=mail@example.com
USE_ENCRYPTION=true
# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates.
# Please note that this will only work for paid fixer.io accounts because they severly limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
# If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here.
ANALYTICS_ID=
# Most parts of the database are encrypted by default, but you can turn this off if you want to.
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
USE_ENCRYPTION=false
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_PREFIX=firefly_tst
SEARCH_RESULT_LIMIT=50
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_ID=
DEMO_USERNAME=
DEMO_PASSWORD=
IS_DOCKER=false
IS_SANDSTORM=false
IS_HEROKU=false

View File

@@ -1,3 +1,65 @@
# 4.7.2
- [Issue 1123](https://github.com/firefly-iii/firefly-iii/issues/1123) First browser based update routine.
- Add support for Italian.
- [Issue 1232](https://github.com/firefly-iii/firefly-iii/issues/1232) Allow user to specify Docker database port.
- [Issue 1197](https://github.com/firefly-iii/firefly-iii/issues/1197) Beter account list overview
- [Issue 1202](https://github.com/firefly-iii/firefly-iii/issues/1202) Some budgetary warnings
- [Issue 1284](https://github.com/firefly-iii/firefly-iii/issues/1284) Experimental support for bunq import
- [Issue 1248](https://github.com/firefly-iii/firefly-iii/issues/1248) Ability to import BIC, ability to import SEPA fields.
- [Issue 1102](https://github.com/firefly-iii/firefly-iii/issues/1102) Summary line for bills
- More info to debug page.
- [Issue 1186](https://github.com/firefly-iii/firefly-iii/issues/1186) You can see the latest account balance in CRUD forms
- Add Kubernetes YAML files, kindly created by a FF3 user.
- [Issue 1244](https://github.com/firefly-iii/firefly-iii/issues/1244) Better line for "today" marker and add it to other chart as well ([issue 1214](https://github.com/firefly-iii/firefly-iii/issues/1214))
- [Issue 1219](https://github.com/firefly-iii/firefly-iii/issues/1219) Languages in dropdown
- [Issue 1189](https://github.com/firefly-iii/firefly-iii/issues/1189) Inactive accounts get removed from net worth
- [Issue 1220](https://github.com/firefly-iii/firefly-iii/issues/1220) Attachment description and notes migrated to just "notes".
- [Issue 1236](https://github.com/firefly-iii/firefly-iii/issues/1236) Multi currency balance box
- [Issue 1240](https://github.com/firefly-iii/firefly-iii/issues/1240) Better overview for accounts.
- [Issue 1292](https://github.com/firefly-iii/firefly-iii/issues/1292) Removed some charts from the "all"-overview of budgets and categories
- [Issue 1245](https://github.com/firefly-iii/firefly-iii/issues/1245) Improved recognition of IBANs
- Improved import routine.
- Update notifier will wait three days before notifying users.
- [Issue 1300](https://github.com/firefly-iii/firefly-iii/issues/1300) Virtual balance of credit cards does not count for net worth
- [Issue 1247](https://github.com/firefly-iii/firefly-iii/issues/1247) Can now see overspent amount
- [Issue 1221](https://github.com/firefly-iii/firefly-iii/issues/1221) Upgrade to Laravel 5.6
- [Issue 1187](https://github.com/firefly-iii/firefly-iii/issues/1187) Updated the password verifier to use Troy Hunt's new API
- Revenue chart is now on frontpage permanently
- [Issue 1153](https://github.com/firefly-iii/firefly-iii/issues/1153) 2FA settings are in your profile now
- [Issue 1227](https://github.com/firefly-iii/firefly-iii/issues/1227) Can set the timezone in config or in Docker
- [Issue 1294](https://github.com/firefly-iii/firefly-iii/issues/1294) Ability to link a transaction to itself
- Correct reference to journal description in split form.
- [Issue 1234](https://github.com/firefly-iii/firefly-iii/issues/1234) Fix budget page issues in SQLite
- [Issue 1262](https://github.com/firefly-iii/firefly-iii/issues/1262) Can now use double and epty headers in CSV files
- [Issue 1258](https://github.com/firefly-iii/firefly-iii/issues/1258) Fixed a possible date mismatch in piggy banks
- [Issue 1283](https://github.com/firefly-iii/firefly-iii/issues/1283) Bulk delete was broken
- [Issue 1293](https://github.com/firefly-iii/firefly-iii/issues/1293) Layout problem with notes
- [Issue 1257](https://github.com/firefly-iii/firefly-iii/issues/1257) Improve transaction lists query count
- [Issue 1291](https://github.com/firefly-iii/firefly-iii/issues/1291) Fixer IO problems
- [Issue 1239](https://github.com/firefly-iii/firefly-iii/issues/1239) Could not edit expense or revenue accounts ([issue 1298](https://github.com/firefly-iii/firefly-iii/issues/1298))
- [Issue 1297](https://github.com/firefly-iii/firefly-iii/issues/1297) Could not convert to withdrawal
- [Issue 1226](https://github.com/firefly-iii/firefly-iii/issues/1226) Category overview in default report shows no income.
- Various other bugs and problems ([issue 1198](https://github.com/firefly-iii/firefly-iii/issues/1198), [issue 1213](https://github.com/firefly-iii/firefly-iii/issues/1213), [issue 1237](https://github.com/firefly-iii/firefly-iii/issues/1237), [issue 1238](https://github.com/firefly-iii/firefly-iii/issues/1238), [issue 1199](https://github.com/firefly-iii/firefly-iii/issues/1199), [issue 1200](https://github.com/firefly-iii/firefly-iii/issues/1200))
### Security
- Fixed an issue with token validation on the command line.
# 4.7.1
- A brand new API. Read about it in the [documentation](http://firefly-iii.readthedocs.io/en/latest/).
- Add support for Spanish. [issue 1194](https://github.com/firefly-iii/firefly-iii/issues/1194)
- Some custom preferences are selected by default for a better user experience.
- Some new currencies [issue 1211](https://github.com/firefly-iii/firefly-iii/issues/1211)
- Fixed [issue 1155](https://github.com/firefly-iii/firefly-iii/issues/1155) (reported by [ndandanov](https://github.com/ndandanov))
- [Issue 1156](https://github.com/firefly-iii/firefly-iii/issues/1156) [issue 1182](https://github.com/firefly-iii/firefly-iii/issues/1182) and other issues related to SQLite databases.
- Multi-page budget overview was broken (reported by [jinformatique](https://github.com/jinformatique))
- Importing CSV files with semi-colons in them did not work [issue 1172](https://github.com/firefly-iii/firefly-iii/issues/1172) [issue 1183](https://github.com/firefly-iii/firefly-iii/issues/1183) [issue 1210](https://github.com/firefly-iii/firefly-iii/issues/1210)
- Could not use account number that was in use by a deleted account [issue 1174](https://github.com/firefly-iii/firefly-iii/issues/1174)
- Fixed spelling error that lead to 404's [issue 1175](https://github.com/firefly-iii/firefly-iii/issues/1175) [issue 1190](https://github.com/firefly-iii/firefly-iii/issues/1190)
- Fixed tag autocomplete [issue 1178](https://github.com/firefly-iii/firefly-iii/issues/1178)
- Better links for "new transaction" buttons [issue 1185](https://github.com/firefly-iii/firefly-iii/issues/1185)
- Cache errors in budget charts [issue 1192](https://github.com/firefly-iii/firefly-iii/issues/1192)
- Deleting transactions that are linked to other other transactions would lead to errors [issue 1209](https://github.com/firefly-iii/firefly-iii/issues/1209)
# 4.7.0
- Support for Russian and Portuguese (Brazil)
- Support for the Spectre API (Salt Edge)

View File

@@ -202,6 +202,7 @@ lib/x86_64-linux-gnu/libz.so.1.2.8
lib64/ld-linux-x86-64.so.2
opt/app/.codeclimate.yml
opt/app/.env
opt/app/.env.current
opt/app/.env.docker
opt/app/.env.example
opt/app/.env.heroku
@@ -240,6 +241,17 @@ opt/app/.sandstorm/setup.sh
opt/app/.sandstorm/stack
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/BillController.php
opt/app/app/Api/V1/Controllers/Controller.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/BillRequest.php
opt/app/app/Api/V1/Requests/Request.php
opt/app/app/Api/V1/Requests/TransactionRequest.php
opt/app/app/Api/V1/Requests/UserRequest.php
opt/app/app/Console/Commands/CreateExport.php
opt/app/app/Console/Commands/CreateImport.php
opt/app/app/Console/Commands/DecryptAttachment.php
@@ -274,6 +286,19 @@ opt/app/app/Export/Exporter/BasicExporter.php
opt/app/app/Export/Exporter/CsvExporter.php
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/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/TagFactory.php
opt/app/app/Factory/TransactionCurrencyFactory.php
opt/app/app/Factory/TransactionFactory.php
opt/app/app/Factory/TransactionJournalFactory.php
opt/app/app/Factory/TransactionJournalMetaFactory.php
opt/app/app/Factory/TransactionTypeFactory.php
opt/app/app/Generator/Chart/Basic/ChartJsGenerator.php
opt/app/app/Generator/Chart/Basic/GeneratorInterface.php
opt/app/app/Generator/Report/Account/MonthReportGenerator.php
@@ -437,7 +462,8 @@ opt/app/app/Http/Requests/MassEditJournalRequest.php
opt/app/app/Http/Requests/NewUserFormRequest.php
opt/app/app/Http/Requests/PiggyBankFormRequest.php
opt/app/app/Http/Requests/ProfileFormRequest.php
opt/app/app/Http/Requests/ReconciliationFormRequest.php
opt/app/app/Http/Requests/ReconciliationStoreRequest.php
opt/app/app/Http/Requests/ReconciliationUpdateRequest.php
opt/app/app/Http/Requests/ReportFormRequest.php
opt/app/app/Http/Requests/Request.php
opt/app/app/Http/Requests/RuleFormRequest.php
@@ -577,13 +603,10 @@ opt/app/app/Repositories/ExportJob/ExportJobRepository.php
opt/app/app/Repositories/ExportJob/ExportJobRepositoryInterface.php
opt/app/app/Repositories/ImportJob/ImportJobRepository.php
opt/app/app/Repositories/ImportJob/ImportJobRepositoryInterface.php
opt/app/app/Repositories/Journal/CreateJournalsTrait.php
opt/app/app/Repositories/Journal/JournalRepository.php
opt/app/app/Repositories/Journal/JournalRepositoryInterface.php
opt/app/app/Repositories/Journal/JournalTasker.php
opt/app/app/Repositories/Journal/JournalTaskerInterface.php
opt/app/app/Repositories/Journal/SupportJournalsTrait.php
opt/app/app/Repositories/Journal/UpdateJournalsTrait.php
opt/app/app/Repositories/LinkType/LinkTypeRepository.php
opt/app/app/Repositories/LinkType/LinkTypeRepositoryInterface.php
opt/app/app/Repositories/PiggyBank/PiggyBankRepository.php
@@ -594,8 +617,13 @@ 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/UniqueIban.php
opt/app/app/Rules/ValidTransactions.php
opt/app/app/Services/Bunq/Id/BunqId.php
opt/app/app/Services/Bunq/Id/DeviceServerId.php
opt/app/app/Services/Bunq/Id/DeviceSessionId.php
@@ -630,6 +658,17 @@ opt/app/app/Services/Github/Object/GithubObject.php
opt/app/app/Services/Github/Object/Release.php
opt/app/app/Services/Github/Request/GithubRequest.php
opt/app/app/Services/Github/Request/UpdateRequest.php
opt/app/app/Services/Internal/Destroy/AccountDestroyService.php
opt/app/app/Services/Internal/Destroy/BillDestroyService.php
opt/app/app/Services/Internal/Destroy/JournalDestroyService.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/TransactionServiceTrait.php
opt/app/app/Services/Internal/Update/AccountUpdateService.php
opt/app/app/Services/Internal/Update/BillUpdateService.php
opt/app/app/Services/Internal/Update/JournalUpdateService.php
opt/app/app/Services/Internal/Update/TransactionUpdateService.php
opt/app/app/Services/Password/PwndVerifier.php
opt/app/app/Services/Password/Verifier.php
opt/app/app/Services/Spectre/Exception/DuplicatedCustomerException.php
@@ -754,6 +793,17 @@ opt/app/app/TransactionRules/Triggers/ToAccountStarts.php
opt/app/app/TransactionRules/Triggers/TransactionType.php
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/BillTransformer.php
opt/app/app/Transformers/BudgetTransformer.php
opt/app/app/Transformers/CategoryTransformer.php
opt/app/app/Transformers/JournalMetaTransformer.php
opt/app/app/Transformers/PiggyBankEventTransformer.php
opt/app/app/Transformers/PiggyBankTransformer.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/artisan
@@ -798,6 +848,11 @@ opt/app/database/migrations/2017_04_13_163623_changes_for_v440.php
opt/app/database/migrations/2017_06_02_105232_changes_for_v450.php
opt/app/database/migrations/2017_08_20_062014_changes_for_v470.php
opt/app/database/migrations/2017_11_04_170844_changes_for_v470a.php
opt/app/database/migrations/2018_01_01_000001_create_oauth_auth_codes_table.php
opt/app/database/migrations/2018_01_01_000002_create_oauth_access_tokens_table.php
opt/app/database/migrations/2018_01_01_000003_create_oauth_refresh_tokens_table.php
opt/app/database/migrations/2018_01_01_000004_create_oauth_clients_table.php
opt/app/database/migrations/2018_01_01_000005_create_oauth_personal_access_clients_table.php
opt/app/database/seeds/AccountTypeSeeder.php
opt/app/database/seeds/DatabaseSeeder.php
opt/app/database/seeds/LinkTypeSeeder.php
@@ -806,11 +861,13 @@ opt/app/database/seeds/TransactionCurrencySeeder.php
opt/app/database/seeds/TransactionTypeSeeder.php
opt/app/docker-compose.yml
opt/app/index.php
opt/app/package-lock.json
opt/app/public/.htaccess
opt/app/public/android-chrome-192x192.png
opt/app/public/android-chrome-512x512.png
opt/app/public/apple-touch-icon.png
opt/app/public/browserconfig.xml
opt/app/public/css/app.css
opt/app/public/css/bootstrap-multiselect.css
opt/app/public/css/bootstrap-sortable.css
opt/app/public/css/bootstrap-tagsinput.css
@@ -944,6 +1001,16 @@ opt/app/public/fonts/lato-100.woff
opt/app/public/fonts/lato-100.woff2
opt/app/public/fonts/roboto-light-300.woff
opt/app/public/fonts/roboto-light-300.woff2
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.eot
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.svg
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.ttf
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.woff
opt/app/public/fonts/vendor/bootstrap-sass/bootstrap/glyphicons-halflings-regular.woff2
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.eot
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.svg
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.ttf
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.woff
opt/app/public/fonts/vendor/font-awesome/fontawesome-webfont.woff2
opt/app/public/images/error.png
opt/app/public/images/image.png
opt/app/public/images/loading-small.gif
@@ -956,6 +1023,7 @@ opt/app/public/images/logos/spectre.png
opt/app/public/images/page_green.png
opt/app/public/images/page_white_acrobat.png
opt/app/public/index.php
opt/app/public/js/app.js
opt/app/public/js/ff/accounts/create.js
opt/app/public/js/ff/accounts/edit-reconciliation.js
opt/app/public/js/ff/accounts/edit.js
@@ -1019,8 +1087,6 @@ opt/app/public/js/lib/bootstrap-tagsinput.min.js.map
opt/app/public/js/lib/bootstrap3-typeahead.min.js
opt/app/public/js/lib/daterangepicker.js
opt/app/public/js/lib/html5shiv.min.js
opt/app/public/js/lib/jquery-3.2.1.min.js
opt/app/public/js/lib/jquery-3.2.1.min.map
opt/app/public/js/lib/jquery-ui.min.js
opt/app/public/js/lib/jquery.color-2.1.2.min.js
opt/app/public/js/lib/modernizr-custom.js
@@ -1033,22 +1099,6 @@ 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/bootstrap/config.json
opt/app/public/lib/bootstrap/css/bootstrap.min.css
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff
opt/app/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2
opt/app/public/lib/bootstrap/js/bootstrap.min.js
opt/app/public/lib/font-awesome/css/font-awesome.css
opt/app/public/lib/font-awesome/css/font-awesome.min.css
opt/app/public/lib/font-awesome/fonts/FontAwesome.otf
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.eot
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.svg
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.ttf
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.woff
opt/app/public/lib/font-awesome/fonts/fontawesome-webfont.woff2
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
@@ -1063,15 +1113,28 @@ opt/app/public/lib/leaflet/leaflet.css
opt/app/public/lib/leaflet/leaflet.js
opt/app/public/lib/leaflet/leaflet.js.map
opt/app/public/manifest.json
opt/app/public/mix-manifest.json
opt/app/public/mstile-150x150.png
opt/app/public/report.html
opt/app/public/robots.txt
opt/app/public/safari-pinned-tab.svg
opt/app/public/web.config
opt/app/readme.md
opt/app/resources/assets/js/app.js
opt/app/resources/assets/js/bootstrap.js
opt/app/resources/assets/js/components/ExampleComponent.vue
opt/app/resources/assets/js/components/bills/Index.vue
opt/app/resources/assets/js/components/passport/AuthorizedClients.vue
opt/app/resources/assets/js/components/passport/Clients.vue
opt/app/resources/assets/js/components/passport/PersonalAccessTokens.vue
opt/app/resources/assets/js/lang.js
opt/app/resources/assets/js/messages.js
opt/app/resources/assets/sass/_variables.scss
opt/app/resources/assets/sass/app.scss
opt/app/resources/lang/de_DE/auth.php
opt/app/resources/lang/de_DE/bank.php
opt/app/resources/lang/de_DE/breadcrumbs.php
opt/app/resources/lang/de_DE/components.php
opt/app/resources/lang/de_DE/config.php
opt/app/resources/lang/de_DE/csv.php
opt/app/resources/lang/de_DE/demo.php
@@ -1087,6 +1150,7 @@ opt/app/resources/lang/de_DE/validation.php
opt/app/resources/lang/en_US/auth.php
opt/app/resources/lang/en_US/bank.php
opt/app/resources/lang/en_US/breadcrumbs.php
opt/app/resources/lang/en_US/components.php
opt/app/resources/lang/en_US/config.php
opt/app/resources/lang/en_US/csv.php
opt/app/resources/lang/en_US/demo.php
@@ -1098,9 +1162,25 @@ opt/app/resources/lang/en_US/list.php
opt/app/resources/lang/en_US/pagination.php
opt/app/resources/lang/en_US/passwords.php
opt/app/resources/lang/en_US/validation.php
opt/app/resources/lang/es_ES/auth.php
opt/app/resources/lang/es_ES/bank.php
opt/app/resources/lang/es_ES/breadcrumbs.php
opt/app/resources/lang/es_ES/components.php
opt/app/resources/lang/es_ES/config.php
opt/app/resources/lang/es_ES/csv.php
opt/app/resources/lang/es_ES/demo.php
opt/app/resources/lang/es_ES/firefly.php
opt/app/resources/lang/es_ES/form.php
opt/app/resources/lang/es_ES/import.php
opt/app/resources/lang/es_ES/intro.php
opt/app/resources/lang/es_ES/list.php
opt/app/resources/lang/es_ES/pagination.php
opt/app/resources/lang/es_ES/passwords.php
opt/app/resources/lang/es_ES/validation.php
opt/app/resources/lang/fr_FR/auth.php
opt/app/resources/lang/fr_FR/bank.php
opt/app/resources/lang/fr_FR/breadcrumbs.php
opt/app/resources/lang/fr_FR/components.php
opt/app/resources/lang/fr_FR/config.php
opt/app/resources/lang/fr_FR/csv.php
opt/app/resources/lang/fr_FR/demo.php
@@ -1116,6 +1196,7 @@ opt/app/resources/lang/fr_FR/validation.php
opt/app/resources/lang/id_ID/auth.php
opt/app/resources/lang/id_ID/bank.php
opt/app/resources/lang/id_ID/breadcrumbs.php
opt/app/resources/lang/id_ID/components.php
opt/app/resources/lang/id_ID/config.php
opt/app/resources/lang/id_ID/csv.php
opt/app/resources/lang/id_ID/demo.php
@@ -1130,6 +1211,7 @@ opt/app/resources/lang/id_ID/validation.php
opt/app/resources/lang/nl_NL/auth.php
opt/app/resources/lang/nl_NL/bank.php
opt/app/resources/lang/nl_NL/breadcrumbs.php
opt/app/resources/lang/nl_NL/components.php
opt/app/resources/lang/nl_NL/config.php
opt/app/resources/lang/nl_NL/csv.php
opt/app/resources/lang/nl_NL/demo.php
@@ -1145,6 +1227,7 @@ opt/app/resources/lang/nl_NL/validation.php
opt/app/resources/lang/pl_PL/auth.php
opt/app/resources/lang/pl_PL/bank.php
opt/app/resources/lang/pl_PL/breadcrumbs.php
opt/app/resources/lang/pl_PL/components.php
opt/app/resources/lang/pl_PL/config.php
opt/app/resources/lang/pl_PL/csv.php
opt/app/resources/lang/pl_PL/demo.php
@@ -1160,6 +1243,7 @@ opt/app/resources/lang/pl_PL/validation.php
opt/app/resources/lang/pt_BR/auth.php
opt/app/resources/lang/pt_BR/bank.php
opt/app/resources/lang/pt_BR/breadcrumbs.php
opt/app/resources/lang/pt_BR/components.php
opt/app/resources/lang/pt_BR/config.php
opt/app/resources/lang/pt_BR/csv.php
opt/app/resources/lang/pt_BR/demo.php
@@ -1174,6 +1258,7 @@ opt/app/resources/lang/pt_BR/validation.php
opt/app/resources/lang/ru_RU/auth.php
opt/app/resources/lang/ru_RU/bank.php
opt/app/resources/lang/ru_RU/breadcrumbs.php
opt/app/resources/lang/ru_RU/components.php
opt/app/resources/lang/ru_RU/config.php
opt/app/resources/lang/ru_RU/csv.php
opt/app/resources/lang/ru_RU/demo.php
@@ -1188,6 +1273,7 @@ opt/app/resources/lang/ru_RU/validation.php
opt/app/resources/lang/tr_TR/auth.php
opt/app/resources/lang/tr_TR/bank.php
opt/app/resources/lang/tr_TR/breadcrumbs.php
opt/app/resources/lang/tr_TR/components.php
opt/app/resources/lang/tr_TR/config.php
opt/app/resources/lang/tr_TR/csv.php
opt/app/resources/lang/tr_TR/demo.php
@@ -1431,6 +1517,7 @@ opt/app/resources/views/transactions/single/create.twig
opt/app/resources/views/transactions/single/delete.twig
opt/app/resources/views/transactions/single/edit.twig
opt/app/resources/views/transactions/split/edit.twig
opt/app/resources/views/vendor/passport/authorize.twig
opt/app/routes/api.php
opt/app/routes/breadcrumbs.php
opt/app/routes/channels.php
@@ -1501,6 +1588,7 @@ opt/app/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php
opt/app/vendor/bacon/bacon-qr-code/tests/bootstrap.php
opt/app/vendor/bin/commonmark
opt/app/vendor/bin/doctrine-dbal
opt/app/vendor/bin/generate-defuse-key
opt/app/vendor/composer/ClassLoader.php
opt/app/vendor/composer/LICENSE
opt/app/vendor/composer/autoload_classmap.php
@@ -1528,6 +1616,39 @@ opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/bulma.blade.php
opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/foundation6.blade.php
opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/json-ld.php
opt/app/vendor/davejamesmiller/laravel-breadcrumbs/views/materialize.blade.php
opt/app/vendor/defuse/php-encryption/.php_cs
opt/app/vendor/defuse/php-encryption/LICENSE
opt/app/vendor/defuse/php-encryption/README.md
opt/app/vendor/defuse/php-encryption/bin/generate-defuse-key
opt/app/vendor/defuse/php-encryption/composer.json
opt/app/vendor/defuse/php-encryption/dist/Makefile
opt/app/vendor/defuse/php-encryption/dist/box.json
opt/app/vendor/defuse/php-encryption/dist/signingkey.asc
opt/app/vendor/defuse/php-encryption/docs/CryptoDetails.md
opt/app/vendor/defuse/php-encryption/docs/FAQ.md
opt/app/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md
opt/app/vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md
opt/app/vendor/defuse/php-encryption/docs/Tutorial.md
opt/app/vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md
opt/app/vendor/defuse/php-encryption/docs/classes/Crypto.md
opt/app/vendor/defuse/php-encryption/docs/classes/File.md
opt/app/vendor/defuse/php-encryption/docs/classes/Key.md
opt/app/vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md
opt/app/vendor/defuse/php-encryption/psalm.xml
opt/app/vendor/defuse/php-encryption/src/Core.php
opt/app/vendor/defuse/php-encryption/src/Crypto.php
opt/app/vendor/defuse/php-encryption/src/DerivedKeys.php
opt/app/vendor/defuse/php-encryption/src/Encoding.php
opt/app/vendor/defuse/php-encryption/src/Exception/BadFormatException.php
opt/app/vendor/defuse/php-encryption/src/Exception/CryptoException.php
opt/app/vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php
opt/app/vendor/defuse/php-encryption/src/Exception/IOException.php
opt/app/vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php
opt/app/vendor/defuse/php-encryption/src/File.php
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
@@ -1995,6 +2116,101 @@ opt/app/vendor/fideloper/proxy/composer.json
opt/app/vendor/fideloper/proxy/config/trustedproxy.php
opt/app/vendor/fideloper/proxy/src/TrustProxies.php
opt/app/vendor/fideloper/proxy/src/TrustedProxyServiceProvider.php
opt/app/vendor/firebase/php-jwt/LICENSE
opt/app/vendor/firebase/php-jwt/README.md
opt/app/vendor/firebase/php-jwt/composer.json
opt/app/vendor/firebase/php-jwt/src/BeforeValidException.php
opt/app/vendor/firebase/php-jwt/src/ExpiredException.php
opt/app/vendor/firebase/php-jwt/src/JWT.php
opt/app/vendor/firebase/php-jwt/src/SignatureInvalidException.php
opt/app/vendor/guzzlehttp/guzzle/CHANGELOG.md
opt/app/vendor/guzzlehttp/guzzle/LICENSE
opt/app/vendor/guzzlehttp/guzzle/README.md
opt/app/vendor/guzzlehttp/guzzle/UPGRADING.md
opt/app/vendor/guzzlehttp/guzzle/composer.json
opt/app/vendor/guzzlehttp/guzzle/src/Client.php
opt/app/vendor/guzzlehttp/guzzle/src/ClientInterface.php
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
opt/app/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
opt/app/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
opt/app/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
opt/app/vendor/guzzlehttp/guzzle/src/HandlerStack.php
opt/app/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
opt/app/vendor/guzzlehttp/guzzle/src/Middleware.php
opt/app/vendor/guzzlehttp/guzzle/src/Pool.php
opt/app/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
opt/app/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
opt/app/vendor/guzzlehttp/guzzle/src/RequestOptions.php
opt/app/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
opt/app/vendor/guzzlehttp/guzzle/src/TransferStats.php
opt/app/vendor/guzzlehttp/guzzle/src/UriTemplate.php
opt/app/vendor/guzzlehttp/guzzle/src/functions.php
opt/app/vendor/guzzlehttp/guzzle/src/functions_include.php
opt/app/vendor/guzzlehttp/promises/CHANGELOG.md
opt/app/vendor/guzzlehttp/promises/LICENSE
opt/app/vendor/guzzlehttp/promises/Makefile
opt/app/vendor/guzzlehttp/promises/README.md
opt/app/vendor/guzzlehttp/promises/composer.json
opt/app/vendor/guzzlehttp/promises/src/AggregateException.php
opt/app/vendor/guzzlehttp/promises/src/CancellationException.php
opt/app/vendor/guzzlehttp/promises/src/Coroutine.php
opt/app/vendor/guzzlehttp/promises/src/EachPromise.php
opt/app/vendor/guzzlehttp/promises/src/FulfilledPromise.php
opt/app/vendor/guzzlehttp/promises/src/Promise.php
opt/app/vendor/guzzlehttp/promises/src/PromiseInterface.php
opt/app/vendor/guzzlehttp/promises/src/PromisorInterface.php
opt/app/vendor/guzzlehttp/promises/src/RejectedPromise.php
opt/app/vendor/guzzlehttp/promises/src/RejectionException.php
opt/app/vendor/guzzlehttp/promises/src/TaskQueue.php
opt/app/vendor/guzzlehttp/promises/src/TaskQueueInterface.php
opt/app/vendor/guzzlehttp/promises/src/functions.php
opt/app/vendor/guzzlehttp/promises/src/functions_include.php
opt/app/vendor/guzzlehttp/psr7/CHANGELOG.md
opt/app/vendor/guzzlehttp/psr7/LICENSE
opt/app/vendor/guzzlehttp/psr7/README.md
opt/app/vendor/guzzlehttp/psr7/composer.json
opt/app/vendor/guzzlehttp/psr7/src/AppendStream.php
opt/app/vendor/guzzlehttp/psr7/src/BufferStream.php
opt/app/vendor/guzzlehttp/psr7/src/CachingStream.php
opt/app/vendor/guzzlehttp/psr7/src/DroppingStream.php
opt/app/vendor/guzzlehttp/psr7/src/FnStream.php
opt/app/vendor/guzzlehttp/psr7/src/InflateStream.php
opt/app/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
opt/app/vendor/guzzlehttp/psr7/src/LimitStream.php
opt/app/vendor/guzzlehttp/psr7/src/MessageTrait.php
opt/app/vendor/guzzlehttp/psr7/src/MultipartStream.php
opt/app/vendor/guzzlehttp/psr7/src/NoSeekStream.php
opt/app/vendor/guzzlehttp/psr7/src/PumpStream.php
opt/app/vendor/guzzlehttp/psr7/src/Request.php
opt/app/vendor/guzzlehttp/psr7/src/Response.php
opt/app/vendor/guzzlehttp/psr7/src/ServerRequest.php
opt/app/vendor/guzzlehttp/psr7/src/Stream.php
opt/app/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
opt/app/vendor/guzzlehttp/psr7/src/StreamWrapper.php
opt/app/vendor/guzzlehttp/psr7/src/UploadedFile.php
opt/app/vendor/guzzlehttp/psr7/src/Uri.php
opt/app/vendor/guzzlehttp/psr7/src/UriNormalizer.php
opt/app/vendor/guzzlehttp/psr7/src/UriResolver.php
opt/app/vendor/guzzlehttp/psr7/src/functions.php
opt/app/vendor/guzzlehttp/psr7/src/functions_include.php
opt/app/vendor/laravel/framework/LICENSE.md
opt/app/vendor/laravel/framework/README.md
opt/app/vendor/laravel/framework/composer.json
@@ -2894,6 +3110,70 @@ opt/app/vendor/laravel/framework/src/Illuminate/View/ViewFinderInterface.php
opt/app/vendor/laravel/framework/src/Illuminate/View/ViewName.php
opt/app/vendor/laravel/framework/src/Illuminate/View/ViewServiceProvider.php
opt/app/vendor/laravel/framework/src/Illuminate/View/composer.json
opt/app/vendor/laravel/passport/LICENSE.txt
opt/app/vendor/laravel/passport/composer.json
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000004_create_oauth_clients_table.php
opt/app/vendor/laravel/passport/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php
opt/app/vendor/laravel/passport/readme.md
opt/app/vendor/laravel/passport/resources/assets/js/components/AuthorizedClients.vue
opt/app/vendor/laravel/passport/resources/assets/js/components/Clients.vue
opt/app/vendor/laravel/passport/resources/assets/js/components/PersonalAccessTokens.vue
opt/app/vendor/laravel/passport/resources/views/authorize.blade.php
opt/app/vendor/laravel/passport/src/ApiTokenCookieFactory.php
opt/app/vendor/laravel/passport/src/AuthCode.php
opt/app/vendor/laravel/passport/src/Bridge/AccessToken.php
opt/app/vendor/laravel/passport/src/Bridge/AccessTokenRepository.php
opt/app/vendor/laravel/passport/src/Bridge/AuthCode.php
opt/app/vendor/laravel/passport/src/Bridge/AuthCodeRepository.php
opt/app/vendor/laravel/passport/src/Bridge/Client.php
opt/app/vendor/laravel/passport/src/Bridge/ClientRepository.php
opt/app/vendor/laravel/passport/src/Bridge/FormatsScopesForStorage.php
opt/app/vendor/laravel/passport/src/Bridge/PersonalAccessGrant.php
opt/app/vendor/laravel/passport/src/Bridge/RefreshToken.php
opt/app/vendor/laravel/passport/src/Bridge/RefreshTokenRepository.php
opt/app/vendor/laravel/passport/src/Bridge/Scope.php
opt/app/vendor/laravel/passport/src/Bridge/ScopeRepository.php
opt/app/vendor/laravel/passport/src/Bridge/User.php
opt/app/vendor/laravel/passport/src/Bridge/UserRepository.php
opt/app/vendor/laravel/passport/src/Client.php
opt/app/vendor/laravel/passport/src/ClientRepository.php
opt/app/vendor/laravel/passport/src/Console/ClientCommand.php
opt/app/vendor/laravel/passport/src/Console/InstallCommand.php
opt/app/vendor/laravel/passport/src/Console/KeysCommand.php
opt/app/vendor/laravel/passport/src/Events/AccessTokenCreated.php
opt/app/vendor/laravel/passport/src/Events/RefreshTokenCreated.php
opt/app/vendor/laravel/passport/src/Exceptions/MissingScopeException.php
opt/app/vendor/laravel/passport/src/Guards/TokenGuard.php
opt/app/vendor/laravel/passport/src/HasApiTokens.php
opt/app/vendor/laravel/passport/src/Http/Controllers/AccessTokenController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/ApproveAuthorizationController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/AuthorizationController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/AuthorizedAccessTokenController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/ClientController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/ConvertsPsrResponses.php
opt/app/vendor/laravel/passport/src/Http/Controllers/DenyAuthorizationController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/HandlesOAuthErrors.php
opt/app/vendor/laravel/passport/src/Http/Controllers/PersonalAccessTokenController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/RetrievesAuthRequestFromSession.php
opt/app/vendor/laravel/passport/src/Http/Controllers/ScopeController.php
opt/app/vendor/laravel/passport/src/Http/Controllers/TransientTokenController.php
opt/app/vendor/laravel/passport/src/Http/Middleware/CheckClientCredentials.php
opt/app/vendor/laravel/passport/src/Http/Middleware/CheckForAnyScope.php
opt/app/vendor/laravel/passport/src/Http/Middleware/CheckScopes.php
opt/app/vendor/laravel/passport/src/Http/Middleware/CreateFreshApiToken.php
opt/app/vendor/laravel/passport/src/Passport.php
opt/app/vendor/laravel/passport/src/PassportServiceProvider.php
opt/app/vendor/laravel/passport/src/PersonalAccessClient.php
opt/app/vendor/laravel/passport/src/PersonalAccessTokenFactory.php
opt/app/vendor/laravel/passport/src/PersonalAccessTokenResult.php
opt/app/vendor/laravel/passport/src/RouteRegistrar.php
opt/app/vendor/laravel/passport/src/Scope.php
opt/app/vendor/laravel/passport/src/Token.php
opt/app/vendor/laravel/passport/src/TokenRepository.php
opt/app/vendor/laravel/passport/src/TransientToken.php
opt/app/vendor/laravelcollective/html/CONTRIBUTING.md
opt/app/vendor/laravelcollective/html/LICENSE.txt
opt/app/vendor/laravelcollective/html/composer.json
@@ -2906,6 +3186,83 @@ opt/app/vendor/laravelcollective/html/src/HtmlBuilder.php
opt/app/vendor/laravelcollective/html/src/HtmlFacade.php
opt/app/vendor/laravelcollective/html/src/HtmlServiceProvider.php
opt/app/vendor/laravelcollective/html/src/helpers.php
opt/app/vendor/lcobucci/jwt/LICENSE
opt/app/vendor/lcobucci/jwt/README.md
opt/app/vendor/lcobucci/jwt/composer.json
opt/app/vendor/lcobucci/jwt/composer.lock
opt/app/vendor/lcobucci/jwt/phpunit.xml.dist
opt/app/vendor/lcobucci/jwt/src/Builder.php
opt/app/vendor/lcobucci/jwt/src/Claim.php
opt/app/vendor/lcobucci/jwt/src/Claim/Basic.php
opt/app/vendor/lcobucci/jwt/src/Claim/EqualsTo.php
opt/app/vendor/lcobucci/jwt/src/Claim/Factory.php
opt/app/vendor/lcobucci/jwt/src/Claim/GreaterOrEqualsTo.php
opt/app/vendor/lcobucci/jwt/src/Claim/LesserOrEqualsTo.php
opt/app/vendor/lcobucci/jwt/src/Claim/Validatable.php
opt/app/vendor/lcobucci/jwt/src/Parser.php
opt/app/vendor/lcobucci/jwt/src/Parsing/Decoder.php
opt/app/vendor/lcobucci/jwt/src/Parsing/Encoder.php
opt/app/vendor/lcobucci/jwt/src/Signature.php
opt/app/vendor/lcobucci/jwt/src/Signer.php
opt/app/vendor/lcobucci/jwt/src/Signer/BaseSigner.php
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa.php
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/KeyParser.php
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha384.php
opt/app/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha512.php
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac.php
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac/Sha384.php
opt/app/vendor/lcobucci/jwt/src/Signer/Hmac/Sha512.php
opt/app/vendor/lcobucci/jwt/src/Signer/Key.php
opt/app/vendor/lcobucci/jwt/src/Signer/Keychain.php
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa.php
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa/Sha384.php
opt/app/vendor/lcobucci/jwt/src/Signer/Rsa/Sha512.php
opt/app/vendor/lcobucci/jwt/src/Token.php
opt/app/vendor/lcobucci/jwt/src/ValidationData.php
opt/app/vendor/lcobucci/jwt/test/functional/EcdsaTokenTest.php
opt/app/vendor/lcobucci/jwt/test/functional/HmacTokenTest.php
opt/app/vendor/lcobucci/jwt/test/functional/Keys.php
opt/app/vendor/lcobucci/jwt/test/functional/RsaTokenTest.php
opt/app/vendor/lcobucci/jwt/test/functional/UnsignedTokenTest.php
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/private.key
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/private2.key
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/public1.key
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/public2.key
opt/app/vendor/lcobucci/jwt/test/functional/ecdsa/public3.key
opt/app/vendor/lcobucci/jwt/test/functional/rsa/encrypted-private.key
opt/app/vendor/lcobucci/jwt/test/functional/rsa/encrypted-public.key
opt/app/vendor/lcobucci/jwt/test/functional/rsa/private.key
opt/app/vendor/lcobucci/jwt/test/functional/rsa/public.key
opt/app/vendor/lcobucci/jwt/test/unit/BuilderTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Claim/BasicTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Claim/EqualsToTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Claim/FactoryTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Claim/GreaterOrEqualsToTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Claim/LesserOrEqualsToTest.php
opt/app/vendor/lcobucci/jwt/test/unit/ParserTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Parsing/DecoderTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Parsing/EncoderTest.php
opt/app/vendor/lcobucci/jwt/test/unit/SignatureTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/BaseSignerTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/KeyParserTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/Sha256Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/Sha384Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Ecdsa/Sha512Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/EcdsaTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Hmac/Sha256Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Hmac/Sha384Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Hmac/Sha512Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/HmacTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/KeyTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/KeychainTest.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Rsa/Sha256Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Rsa/Sha384Test.php
opt/app/vendor/lcobucci/jwt/test/unit/Signer/Rsa/Sha512Test.php
opt/app/vendor/lcobucci/jwt/test/unit/TokenTest.php
opt/app/vendor/lcobucci/jwt/test/unit/ValidationDataTest.php
opt/app/vendor/league/commonmark/.styleci.yml
opt/app/vendor/league/commonmark/CHANGELOG.md
opt/app/vendor/league/commonmark/CONDUCT.md
@@ -3043,47 +3400,28 @@ opt/app/vendor/league/csv/src/Writer.php
opt/app/vendor/league/csv/src/XMLConverter.php
opt/app/vendor/league/csv/src/functions.php
opt/app/vendor/league/csv/src/functions_include.php
opt/app/vendor/league/event/LICENCE
opt/app/vendor/league/event/composer.json
opt/app/vendor/league/event/src/AbstractEvent.php
opt/app/vendor/league/event/src/AbstractListener.php
opt/app/vendor/league/event/src/CallbackListener.php
opt/app/vendor/league/event/src/Emitter.php
opt/app/vendor/league/event/src/EmitterAwareInterface.php
opt/app/vendor/league/event/src/EmitterAwareTrait.php
opt/app/vendor/league/event/src/EmitterInterface.php
opt/app/vendor/league/event/src/EmitterTrait.php
opt/app/vendor/league/event/src/Event.php
opt/app/vendor/league/event/src/EventInterface.php
opt/app/vendor/league/event/src/Generator.php
opt/app/vendor/league/event/src/GeneratorInterface.php
opt/app/vendor/league/event/src/GeneratorTrait.php
opt/app/vendor/league/event/src/ListenerAcceptor.php
opt/app/vendor/league/event/src/ListenerAcceptorInterface.php
opt/app/vendor/league/event/src/ListenerInterface.php
opt/app/vendor/league/event/src/ListenerProviderInterface.php
opt/app/vendor/league/event/src/OneTimeListener.php
opt/app/vendor/league/flysystem/LICENSE
opt/app/vendor/league/flysystem/composer.json
opt/app/vendor/league/flysystem/docs/CNAME
opt/app/vendor/league/flysystem/docs/_data/images.yml
opt/app/vendor/league/flysystem/docs/_data/menu.yml
opt/app/vendor/league/flysystem/docs/_data/project.yml
opt/app/vendor/league/flysystem/docs/_layouts/default.html
opt/app/vendor/league/flysystem/docs/adapter/aws-s3-v2.md
opt/app/vendor/league/flysystem/docs/adapter/aws-s3-v3.md
opt/app/vendor/league/flysystem/docs/adapter/azure.md
opt/app/vendor/league/flysystem/docs/adapter/copy.md
opt/app/vendor/league/flysystem/docs/adapter/digitalocean-spaces.md
opt/app/vendor/league/flysystem/docs/adapter/dropbox.md
opt/app/vendor/league/flysystem/docs/adapter/ftp.md
opt/app/vendor/league/flysystem/docs/adapter/gridfs.md
opt/app/vendor/league/flysystem/docs/adapter/local.md
opt/app/vendor/league/flysystem/docs/adapter/memory.md
opt/app/vendor/league/flysystem/docs/adapter/null-test.md
opt/app/vendor/league/flysystem/docs/adapter/phpcr.md
opt/app/vendor/league/flysystem/docs/adapter/rackspace.md
opt/app/vendor/league/flysystem/docs/adapter/replicate.md
opt/app/vendor/league/flysystem/docs/adapter/sftp.md
opt/app/vendor/league/flysystem/docs/adapter/webdav.md
opt/app/vendor/league/flysystem/docs/adapter/zip-archive.md
opt/app/vendor/league/flysystem/docs/api.md
opt/app/vendor/league/flysystem/docs/caching.md
opt/app/vendor/league/flysystem/docs/core-concepts.md
opt/app/vendor/league/flysystem/docs/creating-an-adapter.md
opt/app/vendor/league/flysystem/docs/index.md
opt/app/vendor/league/flysystem/docs/installation.md
opt/app/vendor/league/flysystem/docs/integrations.md
opt/app/vendor/league/flysystem/docs/logo/become_a_patron_button.png
opt/app/vendor/league/flysystem/docs/logo/become_a_patron_button@2x.png
opt/app/vendor/league/flysystem/docs/logo/become_a_patron_button@3x.png
opt/app/vendor/league/flysystem/docs/logo/laravel.svg
opt/app/vendor/league/flysystem/docs/mount-manager.md
opt/app/vendor/league/flysystem/docs/performance.md
opt/app/vendor/league/flysystem/docs/plugins.md
opt/app/vendor/league/flysystem/docs/recipes.md
opt/app/vendor/league/flysystem/docs/sponsors.md
opt/app/vendor/league/flysystem/docs/upgrade-to-1.0.0.md
opt/app/vendor/league/flysystem/src/Adapter/AbstractAdapter.php
opt/app/vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php
opt/app/vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php
@@ -3130,7 +3468,81 @@ opt/app/vendor/league/flysystem/src/Util.php
opt/app/vendor/league/flysystem/src/Util/ContentListingFormatter.php
opt/app/vendor/league/flysystem/src/Util/MimeType.php
opt/app/vendor/league/flysystem/src/Util/StreamHasher.php
opt/app/vendor/league/flysystem/wait_for_ftp_service.php
opt/app/vendor/league/fractal/LICENSE
opt/app/vendor/league/fractal/composer.json
opt/app/vendor/league/fractal/src/Manager.php
opt/app/vendor/league/fractal/src/Pagination/Cursor.php
opt/app/vendor/league/fractal/src/Pagination/CursorInterface.php
opt/app/vendor/league/fractal/src/Pagination/DoctrinePaginatorAdapter.php
opt/app/vendor/league/fractal/src/Pagination/IlluminatePaginatorAdapter.php
opt/app/vendor/league/fractal/src/Pagination/PagerfantaPaginatorAdapter.php
opt/app/vendor/league/fractal/src/Pagination/PaginatorInterface.php
opt/app/vendor/league/fractal/src/Pagination/PhalconFrameworkPaginatorAdapter.php
opt/app/vendor/league/fractal/src/Pagination/ZendFrameworkPaginatorAdapter.php
opt/app/vendor/league/fractal/src/ParamBag.php
opt/app/vendor/league/fractal/src/Resource/Collection.php
opt/app/vendor/league/fractal/src/Resource/Item.php
opt/app/vendor/league/fractal/src/Resource/NullResource.php
opt/app/vendor/league/fractal/src/Resource/Primitive.php
opt/app/vendor/league/fractal/src/Resource/ResourceAbstract.php
opt/app/vendor/league/fractal/src/Resource/ResourceInterface.php
opt/app/vendor/league/fractal/src/Scope.php
opt/app/vendor/league/fractal/src/ScopeFactory.php
opt/app/vendor/league/fractal/src/ScopeFactoryInterface.php
opt/app/vendor/league/fractal/src/Serializer/ArraySerializer.php
opt/app/vendor/league/fractal/src/Serializer/DataArraySerializer.php
opt/app/vendor/league/fractal/src/Serializer/JsonApiSerializer.php
opt/app/vendor/league/fractal/src/Serializer/Serializer.php
opt/app/vendor/league/fractal/src/Serializer/SerializerAbstract.php
opt/app/vendor/league/fractal/src/TransformerAbstract.php
opt/app/vendor/league/oauth2-server/.styleci.yml
opt/app/vendor/league/oauth2-server/CONDUCT.md
opt/app/vendor/league/oauth2-server/LICENSE
opt/app/vendor/league/oauth2-server/composer.json
opt/app/vendor/league/oauth2-server/src/AuthorizationServer.php
opt/app/vendor/league/oauth2-server/src/AuthorizationValidators/AuthorizationValidatorInterface.php
opt/app/vendor/league/oauth2-server/src/AuthorizationValidators/BearerTokenValidator.php
opt/app/vendor/league/oauth2-server/src/CryptKey.php
opt/app/vendor/league/oauth2-server/src/CryptTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/AccessTokenEntityInterface.php
opt/app/vendor/league/oauth2-server/src/Entities/AuthCodeEntityInterface.php
opt/app/vendor/league/oauth2-server/src/Entities/ClientEntityInterface.php
opt/app/vendor/league/oauth2-server/src/Entities/RefreshTokenEntityInterface.php
opt/app/vendor/league/oauth2-server/src/Entities/ScopeEntityInterface.php
opt/app/vendor/league/oauth2-server/src/Entities/TokenInterface.php
opt/app/vendor/league/oauth2-server/src/Entities/Traits/AccessTokenTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/Traits/AuthCodeTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/Traits/ClientTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/Traits/EntityTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/Traits/RefreshTokenTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/Traits/TokenEntityTrait.php
opt/app/vendor/league/oauth2-server/src/Entities/UserEntityInterface.php
opt/app/vendor/league/oauth2-server/src/Exception/OAuthServerException.php
opt/app/vendor/league/oauth2-server/src/Exception/UniqueTokenIdentifierConstraintViolationException.php
opt/app/vendor/league/oauth2-server/src/Grant/AbstractAuthorizeGrant.php
opt/app/vendor/league/oauth2-server/src/Grant/AbstractGrant.php
opt/app/vendor/league/oauth2-server/src/Grant/AuthCodeGrant.php
opt/app/vendor/league/oauth2-server/src/Grant/ClientCredentialsGrant.php
opt/app/vendor/league/oauth2-server/src/Grant/GrantTypeInterface.php
opt/app/vendor/league/oauth2-server/src/Grant/ImplicitGrant.php
opt/app/vendor/league/oauth2-server/src/Grant/PasswordGrant.php
opt/app/vendor/league/oauth2-server/src/Grant/RefreshTokenGrant.php
opt/app/vendor/league/oauth2-server/src/Middleware/AuthorizationServerMiddleware.php
opt/app/vendor/league/oauth2-server/src/Middleware/ResourceServerMiddleware.php
opt/app/vendor/league/oauth2-server/src/Repositories/AccessTokenRepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/Repositories/AuthCodeRepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/Repositories/ClientRepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/Repositories/RefreshTokenRepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/Repositories/RepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/Repositories/ScopeRepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/Repositories/UserRepositoryInterface.php
opt/app/vendor/league/oauth2-server/src/RequestEvent.php
opt/app/vendor/league/oauth2-server/src/RequestTypes/AuthorizationRequest.php
opt/app/vendor/league/oauth2-server/src/ResourceServer.php
opt/app/vendor/league/oauth2-server/src/ResponseTypes/AbstractResponseType.php
opt/app/vendor/league/oauth2-server/src/ResponseTypes/BearerTokenResponse.php
opt/app/vendor/league/oauth2-server/src/ResponseTypes/RedirectResponse.php
opt/app/vendor/league/oauth2-server/src/ResponseTypes/ResponseTypeInterface.php
opt/app/vendor/monolog/monolog/.php_cs
opt/app/vendor/monolog/monolog/CHANGELOG.md
opt/app/vendor/monolog/monolog/LICENSE
@@ -3342,6 +3754,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php
opt/app/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/af.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ar.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ar_Shakl.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/az.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/bg.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/bn.php
@@ -3349,6 +3762,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ca.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/cs.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/da.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/de.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/dv_MV.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/el.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/en.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/eo.php
@@ -3368,15 +3782,18 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/id.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/it.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ja.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ka.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/kk.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/km.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ko.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/lt.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/lv.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/mk.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/mn.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ms.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/nl.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/no.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/pl.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ps.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/pt.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/pt_BR.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/ro.php
@@ -3385,6 +3802,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sk.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sl.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sq.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/sr_ME.php
@@ -3397,6 +3815,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/uz.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/vi.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh.php
opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh_TW.php
opt/app/vendor/nesbot/carbon/trigger
opt/app/vendor/paragonie/constant_time_encoding/LICENSE.txt
opt/app/vendor/paragonie/constant_time_encoding/README.md
opt/app/vendor/paragonie/constant_time_encoding/composer.json
@@ -3440,6 +3859,36 @@ opt/app/vendor/paragonie/random_compat/lib/random_int.php
opt/app/vendor/paragonie/random_compat/other/build_phar.php
opt/app/vendor/paragonie/random_compat/psalm-autoload.php
opt/app/vendor/paragonie/random_compat/psalm.xml
opt/app/vendor/phpseclib/phpseclib/AUTHORS
opt/app/vendor/phpseclib/phpseclib/LICENSE
opt/app/vendor/phpseclib/phpseclib/README.md
opt/app/vendor/phpseclib/phpseclib/composer.json
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/File/X509.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SSH1.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php
opt/app/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf
opt/app/vendor/pragmarx/google2fa-laravel/LICENSE
opt/app/vendor/pragmarx/google2fa-laravel/changelog.md
opt/app/vendor/pragmarx/google2fa-laravel/composer.json
@@ -3487,6 +3936,17 @@ opt/app/vendor/psr/container/composer.json
opt/app/vendor/psr/container/src/ContainerExceptionInterface.php
opt/app/vendor/psr/container/src/ContainerInterface.php
opt/app/vendor/psr/container/src/NotFoundExceptionInterface.php
opt/app/vendor/psr/http-message/CHANGELOG.md
opt/app/vendor/psr/http-message/LICENSE
opt/app/vendor/psr/http-message/README.md
opt/app/vendor/psr/http-message/composer.json
opt/app/vendor/psr/http-message/src/MessageInterface.php
opt/app/vendor/psr/http-message/src/RequestInterface.php
opt/app/vendor/psr/http-message/src/ResponseInterface.php
opt/app/vendor/psr/http-message/src/ServerRequestInterface.php
opt/app/vendor/psr/http-message/src/StreamInterface.php
opt/app/vendor/psr/http-message/src/UploadedFileInterface.php
opt/app/vendor/psr/http-message/src/UriInterface.php
opt/app/vendor/psr/log/LICENSE
opt/app/vendor/psr/log/Psr/Log/AbstractLogger.php
opt/app/vendor/psr/log/Psr/Log/InvalidArgumentException.php
@@ -4998,8 +5458,10 @@ opt/app/vendor/symfony/polyfill-util/Binary.php
opt/app/vendor/symfony/polyfill-util/BinaryNoFuncOverload.php
opt/app/vendor/symfony/polyfill-util/BinaryOnFuncOverload.php
opt/app/vendor/symfony/polyfill-util/LICENSE
opt/app/vendor/symfony/polyfill-util/LegacyTestListener.php
opt/app/vendor/symfony/polyfill-util/README.md
opt/app/vendor/symfony/polyfill-util/TestListener.php
opt/app/vendor/symfony/polyfill-util/TestListenerTrait.php
opt/app/vendor/symfony/polyfill-util/composer.json
opt/app/vendor/symfony/process/CHANGELOG.md
opt/app/vendor/symfony/process/Exception/ExceptionInterface.php
@@ -5033,6 +5495,23 @@ opt/app/vendor/symfony/process/Tests/ProcessUtilsTest.php
opt/app/vendor/symfony/process/Tests/SignalListener.php
opt/app/vendor/symfony/process/composer.json
opt/app/vendor/symfony/process/phpunit.xml.dist
opt/app/vendor/symfony/psr-http-message-bridge/CHANGELOG
opt/app/vendor/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php
opt/app/vendor/symfony/psr-http-message-bridge/Factory/HttpFoundationFactory.php
opt/app/vendor/symfony/psr-http-message-bridge/HttpFoundationFactoryInterface.php
opt/app/vendor/symfony/psr-http-message-bridge/HttpMessageFactoryInterface.php
opt/app/vendor/symfony/psr-http-message-bridge/LICENSE
opt/app/vendor/symfony/psr-http-message-bridge/README.md
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/DiactorosFactoryTest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Factory/HttpFoundationFactoryTest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Message.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Response.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/ServerRequest.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Stream.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/UploadedFile.php
opt/app/vendor/symfony/psr-http-message-bridge/Tests/Fixtures/Uri.php
opt/app/vendor/symfony/psr-http-message-bridge/composer.json
opt/app/vendor/symfony/psr-http-message-bridge/phpunit.xml.dist
opt/app/vendor/symfony/routing/Annotation/Route.php
opt/app/vendor/symfony/routing/CHANGELOG.md
opt/app/vendor/symfony/routing/CompiledRoute.php
@@ -5063,6 +5542,7 @@ opt/app/vendor/symfony/routing/Loader/Configurator/Traits/AddTrait.php
opt/app/vendor/symfony/routing/Loader/Configurator/Traits/RouteTrait.php
opt/app/vendor/symfony/routing/Loader/DependencyInjection/ServiceRouterLoader.php
opt/app/vendor/symfony/routing/Loader/DirectoryLoader.php
opt/app/vendor/symfony/routing/Loader/GlobFileLoader.php
opt/app/vendor/symfony/routing/Loader/ObjectRouteLoader.php
opt/app/vendor/symfony/routing/Loader/PhpFileLoader.php
opt/app/vendor/symfony/routing/Loader/XmlFileLoader.php
@@ -5175,10 +5655,13 @@ opt/app/vendor/symfony/routing/Tests/Loader/AnnotationDirectoryLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/AnnotationFileLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/ClosureLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/DirectoryLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/GlobFileLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/ObjectRouteLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/PhpFileLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/XmlFileLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Loader/YamlFileLoaderTest.php
opt/app/vendor/symfony/routing/Tests/Matcher/DumpedRedirectableUrlMatcherTest.php
opt/app/vendor/symfony/routing/Tests/Matcher/DumpedUrlMatcherTest.php
opt/app/vendor/symfony/routing/Tests/Matcher/Dumper/DumperCollectionTest.php
opt/app/vendor/symfony/routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
opt/app/vendor/symfony/routing/Tests/Matcher/Dumper/StaticPrefixCollectionTest.php
@@ -5337,6 +5820,7 @@ opt/app/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/packagelist
opt/app/vendor/symfony/translation/Tests/fixtures/resourcebundle/dat/resources.dat
opt/app/vendor/symfony/translation/Tests/fixtures/resourcebundle/res/en.res
opt/app/vendor/symfony/translation/Tests/fixtures/resources-2.0-clean.xlf
opt/app/vendor/symfony/translation/Tests/fixtures/resources-2.0-multi-segment-unit.xlf
opt/app/vendor/symfony/translation/Tests/fixtures/resources-2.0.xlf
opt/app/vendor/symfony/translation/Tests/fixtures/resources-clean.xlf
opt/app/vendor/symfony/translation/Tests/fixtures/resources-notes-meta.xlf
@@ -5931,6 +6415,7 @@ opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_array_wit
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_undefined_variable.test
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_unknown_argument.test
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_tag_with_undefined_variable.test
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/strict_comparison_operator.test
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/syntax_error_in_reused_template.test
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test
opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_parent.test
@@ -6301,6 +6786,47 @@ opt/app/vendor/watson/validating/src/ValidatingModel.php
opt/app/vendor/watson/validating/src/ValidatingObserver.php
opt/app/vendor/watson/validating/src/ValidatingTrait.php
opt/app/vendor/watson/validating/src/ValidationException.php
opt/app/vendor/zendframework/zend-diactoros/.coveralls.yml
opt/app/vendor/zendframework/zend-diactoros/CHANGELOG.md
opt/app/vendor/zendframework/zend-diactoros/CONDUCT.md
opt/app/vendor/zendframework/zend-diactoros/CONTRIBUTING.md
opt/app/vendor/zendframework/zend-diactoros/LICENSE.md
opt/app/vendor/zendframework/zend-diactoros/README.md
opt/app/vendor/zendframework/zend-diactoros/composer.json
opt/app/vendor/zendframework/zend-diactoros/composer.lock
opt/app/vendor/zendframework/zend-diactoros/mkdocs.yml
opt/app/vendor/zendframework/zend-diactoros/src/AbstractSerializer.php
opt/app/vendor/zendframework/zend-diactoros/src/CallbackStream.php
opt/app/vendor/zendframework/zend-diactoros/src/Exception/DeprecatedMethodException.php
opt/app/vendor/zendframework/zend-diactoros/src/Exception/ExceptionInterface.php
opt/app/vendor/zendframework/zend-diactoros/src/HeaderSecurity.php
opt/app/vendor/zendframework/zend-diactoros/src/MessageTrait.php
opt/app/vendor/zendframework/zend-diactoros/src/PhpInputStream.php
opt/app/vendor/zendframework/zend-diactoros/src/RelativeStream.php
opt/app/vendor/zendframework/zend-diactoros/src/Request.php
opt/app/vendor/zendframework/zend-diactoros/src/Request/ArraySerializer.php
opt/app/vendor/zendframework/zend-diactoros/src/Request/Serializer.php
opt/app/vendor/zendframework/zend-diactoros/src/RequestTrait.php
opt/app/vendor/zendframework/zend-diactoros/src/Response.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/ArraySerializer.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/EmitterInterface.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/EmptyResponse.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/HtmlResponse.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/InjectContentTypeTrait.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/JsonResponse.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/RedirectResponse.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/SapiEmitter.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/SapiEmitterTrait.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/SapiStreamEmitter.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/Serializer.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/TextResponse.php
opt/app/vendor/zendframework/zend-diactoros/src/Response/XmlResponse.php
opt/app/vendor/zendframework/zend-diactoros/src/Server.php
opt/app/vendor/zendframework/zend-diactoros/src/ServerRequest.php
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
proc/cpuinfo
sandstorm-http-bridge
sandstorm-http-bridge-config

View File

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

View File

@@ -1,7 +1,6 @@
language: php
php:
- 7.1
- 7.2
cache:
directories:
@@ -13,21 +12,19 @@ install:
- composer update --no-scripts
- cp .env.testing .env
- php artisan clear-compiled
- php artisan optimize
- php artisan env
- cp .env.testing .env
- wget -q https://github.com/firefly-iii/test-data/raw/master/storage/database.sqlite -O storage/database/database.sqlite
- mkdir -p build/logs
script:
- phpunit -c phpunit.coverage.xml
- ./vendor/bin/phpunit -c phpunit.coverage.xml
after_success:
- travis_retry php vendor/bin/php-coveralls -x storage/build/clover-all.xml
- bash <(curl -s https://codecov.io/bash) -f storage/build/clover-all.xml
# safelist
branches:
only:
- develop
- master
- master

View File

@@ -31,7 +31,7 @@ RUN docker-php-ext-install -j$(nproc) curl gd intl json readline tidy zip bcmath
RUN echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
# copy Apache config to correct spot.
COPY ./docker/apache2.conf /etc/apache2/apache2.conf
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
# Enable apache mod rewrite..
RUN a2enmod rewrite
@@ -46,7 +46,7 @@ VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Enable default site (Firefly III)
COPY ./docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
# Make sure we own Firefly III directory
RUN chown -R www-data:www-data /var/www && chmod -R 775 $FIREFLY_PATH/storage
@@ -58,4 +58,4 @@ RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest
EXPOSE 80
# Run entrypoint thing
ENTRYPOINT ["docker/entrypoint.sh"]
ENTRYPOINT [".deploy/docker/entrypoint.sh"]

View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/**
* AboutController.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\Api\V1\Controllers;
use DB;
use FireflyIII\Transformers\UserTransformer;
use Illuminate\Http\Request;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AboutController
*/
class AboutController extends Controller
{
/**
* AccountController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function about()
{
$search = ['~', '#'];
$replace = ['\~', '# '];
$phpVersion = str_replace($search, $replace, PHP_VERSION);
$phpOs = str_replace($search, $replace, PHP_OS);
$currentDriver = DB::getDriverName();
$data
= [
'version' => config('firefly.version'),
'api_version' => config('firefly.api_version'),
'php_version' => $phpVersion,
'os' => $phpOs,
'driver' => $currentDriver,
];
return response()->json(['data' => $data], 200)->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function user(Request $request)
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item(auth()->user(), new UserTransformer($this->parameters), 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@@ -0,0 +1,261 @@
<?php
declare(strict_types=1);
/**
* AccountController.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\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\AccountRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
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 Preferences;
/**
* Class AccountController
*/
class AccountController extends Controller
{
/** @var CurrencyRepositoryInterface */
private $currencyRepository;
/** @var AccountRepositoryInterface */
private $repository;
/**
* AccountController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
// @var AccountRepositoryInterface repository
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param \FireflyIII\Models\Account $account
*
* @return \Illuminate\Http\Response
*/
public function delete(Account $account)
{
$this->repository->destroy($account, null);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
// create some objects:
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// read type from URI
$type = $request->get('type') ?? 'all';
$this->parameters->set('type', $type);
// types to get, page size:
$types = $this->mapTypes($this->parameters->get('type'));
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
// get list of accounts. Count it and split it.
$collection = $this->repository->getAccountsByType($types);
$count = $collection->count();
$accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.accounts.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($accounts, new AccountTransformer($this->parameters), 'accounts');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Account $account
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request, Account $account)
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($account, new AccountTransformer($this->parameters), 'accounts');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param AccountRequest $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(AccountRequest $request)
{
$data = $request->getAll();
// if currency ID is 0, find the currency by the code:
if (0 === $data['currency_id']) {
$currency = $this->currencyRepository->findByCodeNull($data['currency_code']);
$data['currency_id'] = is_null($currency) ? 0 : $currency->id;
}
$account = $this->repository->store($data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($account, new AccountTransformer($this->parameters), 'accounts');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update account.
*
* @param AccountRequest $request
* @param Account $account
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(AccountRequest $request, Account $account)
{
$data = $request->getAll();
// if currency ID is 0, find the currency by the code:
if (0 === $data['currency_id']) {
$currency = $this->currencyRepository->findByCodeNull($data['currency_code']);
$data['currency_id'] = is_null($currency) ? 0 : $currency->id;
}
// set correct type:
$data['type'] = config('firefly.shortNamesByFullName.' . $account->accountType->type);
$this->repository->update($account, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($account, new AccountTransformer($this->parameters), 'accounts');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @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,
],
AccountType::DEFAULT => [AccountType::DEFAULT],
AccountType::CASH => [AccountType::CASH],
AccountType::ASSET => [AccountType::ASSET],
AccountType::EXPENSE => [AccountType::EXPENSE],
AccountType::REVENUE => [AccountType::REVENUE],
AccountType::INITIAL_BALANCE => [AccountType::INITIAL_BALANCE],
AccountType::BENEFICIARY => [AccountType::BENEFICIARY],
AccountType::IMPORT => [AccountType::IMPORT],
AccountType::RECONCILIATION => [AccountType::RECONCILIATION],
AccountType::LOAN => [AccountType::LOAN],
];
if (isset($types[$type])) {
return $types[$type];
}
return $types['all']; // @codeCoverageIgnore
}
}

View File

@@ -0,0 +1,163 @@
<?php
declare(strict_types=1);
/**
* BillController.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\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\BillRequest;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Transformers\BillTransformer;
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\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
* Class BillController
*/
class BillController extends Controller
{
/** @var BillRepositoryInterface */
private $repository;
/**
* BillController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param \FireflyIII\Models\Bill $bill
*
* @return \Illuminate\Http\Response
*/
public function delete(Bill $bill)
{
$this->repository->destroy($bill);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
$paginator = $this->repository->getPaginator($pageSize);
/** @var Collection $bills */
$bills = $paginator->getCollection();
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($bills, new BillTransformer($this->parameters), 'bills');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Bill $bill
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request, Bill $bill)
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param BillRequest $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(BillRequest $request)
{
$bill = $this->repository->store($request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param BillRequest $request
* @param Bill $bill
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(BillRequest $request, Bill $bill)
{
$data = $request->getAll();
$bill = $this->repository->update($bill, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@@ -0,0 +1,124 @@
<?php
declare(strict_types=1);
/**
* Controller.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\Api\V1\Controllers;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException;
use FireflyConfig;
use FireflyIII\Exceptions\FireflyException;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Log;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class Controller.
*
* @codeCoverageIgnore
*/
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/** @var ParameterBag */
protected $parameters;
/**
* Controller constructor.
*
* @throws FireflyException
*/
public function __construct()
{
// is site a demo site?
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
// do not expose API on demo site:
if (true === $isDemoSite) {
throw new FireflyException('The API is not available on the demo site.');
}
// get global parameters
$this->parameters = $this->getParameters();
}
/**
* @return string
*/
protected function buildParams(): string
{
$return = '?';
$params = [];
foreach ($this->parameters as $key => $value) {
if ($key === 'page') {
continue;
}
if ($value instanceof Carbon) {
$params[$key] = $value->format('Y-m-d');
}
if (!$value instanceof Carbon) {
$params[$key] = $value;
}
}
$return .= http_build_query($params);
if (strlen($return) === 1) {
return '';
}
return $return;
}
/**
* @return ParameterBag
*/
private function getParameters(): ParameterBag
{
$bag = new ParameterBag;
$page = (int)request()->get('page');
if ($page === 0) {
$page = 1;
}
$bag->set('page', $page);
// some date fields:
$dates = ['start', 'end', 'date'];
foreach ($dates as $field) {
$date = request()->get($field);
$obj = null;
if (!is_null($date)) {
try {
$obj = new Carbon($date);
} catch (InvalidDateException $e) {
// don't care
Log::error(sprintf('Invalid date exception in API controller: %s', $e->getMessage()));
}
}
$bag->set($field, $obj);
}
return $bag;
}
}

View File

@@ -0,0 +1,334 @@
<?php
declare(strict_types=1);
/**
* TransactionController.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\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\TransactionRequest;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Transformers\TransactionTransformer;
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;
use Preferences;
/**
* Class TransactionController
*/
class TransactionController extends Controller
{
/** @var JournalRepositoryInterface */
private $repository;
/**
* TransactionController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var JournalRepositoryInterface repository */
$this->repository = app(JournalRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param \FireflyIII\Models\Transaction $transaction
*
* @return \Illuminate\Http\Response
*/
public function delete(Transaction $transaction)
{
$journal = $transaction->transactionJournal;
$this->repository->destroy($journal);
return response()->json([], 204);
}
/**
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
// read type from URI
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
// types to get, page size:
$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());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
// remove internal transfer filter:
if (in_array(TransactionType::TRANSFER, $types)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (!is_null($this->parameters->get('start')) && !is_null($this->parameters->get('end'))) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
}
$collector->setLimit($pageSize)->setPage($this->parameters->get('page'));
$collector->setTypes($types);
$paginator = $collector->getPaginatedJournals();
$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));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Transaction $transaction
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request, Transaction $transaction)
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
// collect transactions using the journal collector
$collector = app(JournalCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
$collector->setJournals(new Collection([$transaction->transactionJournal]));
// add filter to remove transactions:
$transactionType = $transaction->transactionJournal->transactionType->type;
if ($transactionType === TransactionType::WITHDRAWAL) {
$collector->addFilter(PositiveAmountFilter::class);
}
if (!($transactionType === TransactionType::WITHDRAWAL)) {
$collector->addFilter(NegativeAmountFilter::class);
}
$transactions = $collector->getJournals();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param TransactionRequest $request
*
* @param JournalRepositoryInterface $repository
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(TransactionRequest $request, JournalRepositoryInterface $repository)
{
$data = $request->getAll();
$data['user'] = auth()->user()->id;
$journal = $repository->store($data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
// collect transactions using the journal collector
$collector = app(JournalCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
$collector->setJournals(new Collection([$journal]));
// add filter to remove transactions:
$transactionType = $journal->transactionType->type;
if ($transactionType === TransactionType::WITHDRAWAL) {
$collector->addFilter(PositiveAmountFilter::class);
}
if (!($transactionType === TransactionType::WITHDRAWAL)) {
$collector->addFilter(NegativeAmountFilter::class);
}
$transactions = $collector->getJournals();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param TransactionRequest $request
* @param JournalRepositoryInterface $repository
* @param Transaction $transaction
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(TransactionRequest $request, JournalRepositoryInterface $repository, Transaction $transaction)
{
$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';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
// 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->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
$collector->setJournals(new Collection([$journal]));
// add filter to remove transactions:
$transactionType = $journal->transactionType->type;
if ($transactionType === TransactionType::WITHDRAWAL) {
$collector->addFilter(PositiveAmountFilter::class);
}
if (!($transactionType === TransactionType::WITHDRAWAL)) {
$collector->addFilter(NegativeAmountFilter::class);
}
$transactions = $collector->getJournals();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @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,
],
];
if (isset($types[$type])) {
return $types[$type];
}
return $types['default']; // @codeCoverageIgnore
}
}

View File

@@ -0,0 +1,193 @@
<?php
declare(strict_types=1);
/**
* UserController.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\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\UserRequest;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Transformers\UserTransformer;
use FireflyIII\User;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
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 Preferences;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
/**
* Class UserController
*/
class UserController extends Controller
{
/** @var UserRepositoryInterface */
private $repository;
/**
* UserController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var UserRepositoryInterface repository */
$this->repository = app(UserRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param \FireflyIII\User $user
*
* @return \Illuminate\Http\Response
* @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException
*/
public function delete(User $user)
{
if (auth()->user()->hasRole('owner')) {
$this->repository->destroy($user);
return response()->json([], 204);
}
throw new AccessDeniedException(''); // @codeCoverageIgnore
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
// user preferences
$pageSize = intval(Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data);
// make manager
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// build collection
$collection = $this->repository->all();
$count = $collection->count();
$users = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($users, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.users.index') . $this->buildParams());
// make resource
$resource = new FractalCollection($users, new UserTransformer($this->parameters), 'users');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param User $user
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request, User $user)
{
// make manager
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
// make resource
$resource = new Item($user, new UserTransformer($this->parameters), 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param UserRequest $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(UserRequest $request)
{
$data = $request->getAll();
$user = $this->repository->store($data);
// make manager
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
// make resource
$resource = new Item($user, new UserTransformer($this->parameters), 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param UserRequest $request
* @param User $user
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(UserRequest $request, User $user)
{
$data = $request->getAll();
$user = $this->repository->update($user, $data);
// make manager
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
// make resource
$resource = new Item($user, new UserTransformer($this->parameters), 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
/**
* AccountRequest.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\Api\V1\Requests;
/**
* Class AccountRequest
*/
class AccountRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
$data = [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'accountType' => $this->string('type'),
'account_type_id' => null,
'currency_id' => $this->integer('currency_id'),
'currency_code' => $this->string('currency_code'),
'virtualBalance' => $this->string('virtual_balance'),
'iban' => $this->string('iban'),
'BIC' => $this->string('bic'),
'accountNumber' => $this->string('account_number'),
'accountRole' => $this->string('account_role'),
'openingBalance' => $this->string('opening_balance'),
'openingBalanceDate' => $this->date('opening_balance_date'),
'ccType' => $this->string('cc_type'),
'ccMonthlyPaymentDate' => $this->string('cc_monthly_payment_date'),
'notes' => $this->string('notes'),
];
return $data;
}
/**
* @return array
*/
public function rules(): array
{
$accountRoles = implode(',', config('firefly.accountRoles'));
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
$rules = [
'name' => 'required|min:1|uniqueAccountForUser',
'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
'iban' => 'iban|nullable',
'bic' => 'bic|nullable',
'virtual_balance' => 'numeric|nullable',
'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',
'account_number' => 'between:1,255|nullable|uniqueAccountNumberForUser',
'account_role' => 'in:' . $accountRoles . '|required_if:type,asset',
'active' => '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',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
$account = $this->route()->parameter('account');
$rules['name'] .= ':' . $account->id;
$rules['account_number'] .= ':' . $account->id;
$rules['type'] = 'in:' . $types;
break;
}
return $rules;
}
}

View File

@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
/**
* BillRequest.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\Api\V1\Requests;
use Illuminate\Validation\Validator;
/**
* Class BillRequest
*/
class BillRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
$data = [
'name' => $this->string('name'),
'match' => $this->string('match'),
'amount_min' => $this->string('amount_min'),
'amount_max' => $this->string('amount_max'),
//'currency_id' => $this->integer('currency_id'),
//'currency_code' => $this->string('currency_code'),
'date' => $this->date('date'),
'repeat_freq' => $this->string('repeat_freq'),
'skip' => $this->integer('skip'),
'automatch' => $this->boolean('automatch'),
'active' => $this->boolean('active'),
'notes' => $this->string('notes'),
];
return $data;
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'name' => 'required|between:1,255|uniqueObjectForUser:bills,name',
'match' => 'required|between:1,255|uniqueObjectForUser:bills,match',
'amount_min' => 'required|numeric|more:0',
'amount_max' => 'required|numeric|more:0',
//'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',
'date' => 'required|date',
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'required|between:0,31',
'automatch' => 'required|boolean',
'active' => 'required|boolean',
'notes' => 'between:1,65536',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
$bill = $this->route()->parameter('bill');
$rules['name'] .= ',' . $bill->id;
$rules['match'] .= ',' . $bill->id;
break;
}
return $rules;
}
/**
* Configure the validator instance.
*
* @param Validator $validator
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
$data = $validator->getData();
$min = floatval($data['amount_min'] ?? 0);
$max = floatval($data['amount_max'] ?? 0);
if ($min > $max) {
$validator->errors()->add('amount_min', trans('validation.amount_min_over_max'));
}
}
);
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
/**
* Request.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\Api\V1\Requests;
use FireflyIII\Http\Requests\Request as FireflyIIIRequest;
/**
* Class Request.
*/
class Request extends FireflyIIIRequest
{
}

View File

@@ -0,0 +1,514 @@
<?php
declare(strict_types=1);
/**
* TransactionRequest.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\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 Illuminate\Validation\Validator;
/**
* Class TransactionRequest
*/
class TransactionRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
$data = [
// basic fields for journal:
'type' => $this->string('type'),
'date' => $this->date('date'),
'description' => $this->string('description'),
'piggy_bank_id' => $this->integer('piggy_bank_id'),
'piggy_bank_name' => $this->string('piggy_bank_name'),
'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'),
'due_date' => $this->date('due_date'),
'payment_date' => $this->date('payment_date'),
'invoice_date' => $this->date('invoice_date'),
'internal_reference' => $this->string('internal_reference'),
'notes' => $this->string('notes'),
// then, transactions (see below).
'transactions' => [],
];
foreach ($this->get('transactions') as $index => $transaction) {
$array = [
'description' => $transaction['description'] ?? null,
'amount' => $transaction['amount'],
'currency_id' => isset($transaction['currency_id']) ? intval($transaction['currency_id']) : null,
'currency_code' => isset($transaction['currency_code']) ? $transaction['currency_code'] : null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? intval($transaction['foreign_currency_id']) : null,
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : null,
'budget_name' => $transaction['budget_name'] ?? null,
'category_id' => isset($transaction['category_id']) ? intval($transaction['category_id']) : null,
'category_name' => $transaction['category_name'] ?? null,
'source_id' => isset($transaction['source_id']) ? intval($transaction['source_id']) : null,
'source_name' => isset($transaction['source_name']) ? strval($transaction['source_name']) : null,
'destination_id' => isset($transaction['destination_id']) ? intval($transaction['destination_id']) : null,
'destination_name' => isset($transaction['destination_name']) ? strval($transaction['destination_name']) : null,
'reconciled' => $transaction['reconciled'] ?? false,
'identifier' => $index,
];
$data['transactions'][] = $array;
}
return $data;
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
// basic fields for journal:
'type' => 'required|in:withdrawal,deposit,transfer',
'date' => 'required|date',
'description' => 'between:1,255',
'piggy_bank_id' => ['numeric', 'nullable', 'mustExist:piggy_banks,id', new BelongsUser],
'piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser],
'bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUser],
'bill_name' => ['between:1,255', 'nullable', new BelongsUser],
'tags' => 'between:1,255',
// then, custom fields for journal
'interest_date' => 'date|nullable',
'book_date' => 'date|nullable',
'process_date' => 'date|nullable',
'due_date' => 'date|nullable',
'payment_date' => 'date|nullable',
'invoice_date' => 'date|nullable',
'internal_reference' => 'min:1,max:255|nullable',
'notes' => 'min:1,max:50000|nullable',
// transaction rules (in array for splits):
'transactions.*.description' => 'nullable|between:1,255',
'transactions.*.amount' => 'required|numeric|more:0',
'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',
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id',
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.reconciled' => 'boolean|nullable',
// basic rules will be expanded later.
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
'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;
}
return $rules;
}
/**
* Configure the validator instance.
*
* @param Validator $validator
*
* @return void
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
$this->atLeastOneTransaction($validator);
$this->checkValidDescriptions($validator);
$this->equalToJournalDescription($validator);
$this->emptySplitDescriptions($validator);
$this->foreignCurrencyInformation($validator);
$this->validateAccountInformation($validator);
$this->validateSplitAccounts($validator);
}
);
}
/**
* Throws an error when this asset account is invalid.
*
* @param Validator $validator
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
* @param string $nameField
*
* @return null|Account
*/
protected function assetAccountExists(Validator $validator, ?int $accountId, ?string $accountName, string $idField, string $nameField): ?Account
{
$accountId = intval($accountId);
$accountName = strval($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;
}
$account = $repository->findByNameNull($accountName, [AccountType::ASSET]);
if (is_null($account)) {
$validator->errors()->add($nameField, trans('validation.belongs_user'));
return null;
}
return $account;
}
/**
* 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)
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
$journalDescription = strval($data['description'] ?? '');
$validDescriptions = 0;
foreach ($transactions as $index => $transaction) {
if (strlen(strval($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 = strval($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 = strval($data['description'] ?? '');
foreach ($transactions as $index => $transaction) {
$description = strval($transaction['description'] ?? '');
// description cannot be equal to journal description.
if ($description === $journalDescription) {
$validator->errors()->add('transactions.' . $index . '.description', trans('validation.equal_description'));
}
}
}
/**
* 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.
*
* @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 = intval($accountId);
$accountName = strval($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 (is_null($transaction)) {
return; // @codeCoverageIgnore
}
$data['type'] = strtolower($transaction->transactionJournal->transactionType->type);
}
foreach ($transactions as $index => $transaction) {
$sourceId = isset($transaction['source_id']) ? intval($transaction['source_id']) : null;
$sourceName = $transaction['source_name'] ?? null;
$destinationId = isset($transaction['destination_id']) ? intval($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)
{
$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']) ? intval($transaction['source_id']) : 0;
$destinations[] = isset($transaction['destination_id']) ? intval($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

@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
/**
* UserRequest.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\Api\V1\Requests;
use FireflyIII\User;
/**
* Class UserRequest
*/
class UserRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
if (!auth()->check()) {
return false; // @codeCoverageIgnore
}
/** @var User $user */
$user = auth()->user();
if (!$user->hasRole('owner')) {
return false; // @codeCoverageIgnore
}
return true;
}
/**
* @return array
*/
public function getAll(): array
{
$data = [
'email' => $this->string('email'),
'blocked' => $this->boolean('blocked'),
'blocked_code' => $this->string('blocked_code'),
];
return $data;
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'email' => 'required|email|unique:users,email,',
'blocked' => 'required|boolean',
'blocked_code' => 'in:email_changed',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
$user = $this->route()->parameter('user');
$rules['email'] = 'required|email|unique:users,email,' . $user->id;
break;
}
return $rules;
}
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* CreateExport.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,7 +19,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -60,17 +60,6 @@ class CreateExport extends Command
{--with_uploads : Include user\'s uploads?}';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five its fine.
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* Execute the console command.
*
* @return mixed
@@ -80,7 +69,7 @@ class CreateExport extends Command
if (!$this->verifyAccessToken()) {
$this->error('Invalid access token.');
return;
return 1;
}
$this->line('Full export is running...');
// make repositories
@@ -94,7 +83,7 @@ class CreateExport extends Command
$journalRepository = app(JournalRepositoryInterface::class);
// set user
$user = $userRepository->find(intval($this->option('user')));
$user = $userRepository->findNull((int)$this->option('user'));
$jobRepository->setUser($user);
$journalRepository->setUser($user);
$accountRepository->setUser($user);
@@ -140,7 +129,5 @@ class CreateExport extends Command
$this->line('The export has finished! You can find the ZIP file in this location:');
$this->line(storage_path(sprintf('export/%s', $fileName)));
return;
}
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* CreateImport.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,20 +19,17 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use Artisan;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Import\Routine\RoutineInterface;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Services\Internal\File\EncryptService;
use Illuminate\Console\Command;
use Illuminate\Support\MessageBag;
use Log;
use Monolog\Formatter\LineFormatter;
use Preferences;
/**
@@ -61,76 +59,67 @@ class CreateImport extends Command
{--token= : The user\'s access token.}
{--start : Starts the job immediately.}';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* Run the command.
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) // cannot be helped
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five exactly.
* @noinspection MultipleReturnStatementsInspection
*
* @throws FireflyException
*/
public function handle()
public function handle(): int
{
if (!$this->verifyAccessToken()) {
$this->error('Invalid access token.');
$this->errorLine('Invalid access token.');
return;
return 1;
}
/** @var UserRepositoryInterface $userRepository */
$userRepository = app(UserRepositoryInterface::class);
$file = $this->argument('file');
$configuration = $this->argument('configuration');
$user = $userRepository->find(intval($this->option('user')));
$user = $userRepository->findNull((int)$this->option('user'));
$cwd = getcwd();
$type = strtolower($this->option('type'));
if (!$this->validArguments()) {
return;
$this->errorLine('Invalid arguments.');
return 1;
}
$configurationData = json_decode(file_get_contents($configuration), true);
if (null === $configurationData) {
$this->error(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
$this->errorLine(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return;
return 1;
}
$this->line(sprintf('Going to create a job to import file: %s', $file));
$this->line(sprintf('Using configuration file: %s', $configuration));
$this->line(sprintf('Import into user: #%d (%s)', $user->id, $user->email));
$this->line(sprintf('Type of import: %s', $type));
$this->infoLine(sprintf('Going to create a job to import file: %s', $file));
$this->infoLine(sprintf('Using configuration file: %s', $configuration));
$this->infoLine(sprintf('Import into user: #%d (%s)', $user->id, $user->email));
$this->infoLine(sprintf('Type of import: %s', $type));
/** @var ImportJobRepositoryInterface $jobRepository */
$jobRepository = app(ImportJobRepositoryInterface::class);
$jobRepository->setUser($user);
$job = $jobRepository->create($type);
$this->line(sprintf('Created job "%s"', $job->key));
$this->infoLine(sprintf('Created job "%s"', $job->key));
Artisan::call('firefly:encrypt-file', ['file' => $file, 'key' => $job->key]);
$this->line('Stored import data...');
/** @var EncryptService $service */
$service = app(EncryptService::class);
$service->encrypt($file, $job->key);
$this->infoLine('Stored import data...');
$jobRepository->setConfiguration($job, $configurationData);
$jobRepository->updateStatus($job, 'configured');
$this->line('Stored configuration...');
$this->infoLine('Stored configuration...');
if (true === $this->option('start')) {
$this->line('The import will start in a moment. This process is not visible...');
$this->infoLine('The import will start in a moment. This process is not visible...');
Log::debug('Go for import!');
// normally would refer to other firefly:start-import but that doesn't seem to work all to well...
$monolog = Log::getMonolog();
$handler = new CommandHandler($this);
$formatter = new LineFormatter(null, null, false, true);
$handler->setFormatter($formatter);
$monolog->pushHandler($handler);
// start the actual routine:
$type = 'csv' === $job->file_type ? 'file' : $job->file_type;
@@ -147,9 +136,9 @@ class CreateImport extends Command
// give feedback.
/** @var MessageBag $error */
foreach ($routine->getErrors() as $index => $error) {
$this->error(sprintf('Error importing line #%d: %s', $index, $error));
$this->errorLine(sprintf('Error importing line #%d: %s', $index, $error));
}
$this->line(
$this->infoLine(
sprintf(
'The import has finished. %d transactions have been imported out of %d records.', $routine->getJournals()->count(), $routine->getLines()
)
@@ -159,45 +148,58 @@ class CreateImport extends Command
// clear cache for user:
Preferences::setForUser($user, 'lastActivity', microtime());
return;
return 0;
}
/**
* @param string $message
* @param array|null $data
*/
private function errorLine(string $message, array $data = null): void
{
Log::error($message, $data ?? []);
$this->error($message);
}
/**
* @param string $message
* @param array $data
*/
private function infoLine(string $message, array $data = null): void
{
Log::info($message, $data ?? []);
$this->line($message);
}
/**
* Verify user inserts correct arguments.
*
* @noinspection MultipleReturnStatementsInspection
* @return bool
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five exactly.
*/
private function validArguments(): bool
{
/** @var UserRepositoryInterface $userRepository */
$userRepository = app(UserRepositoryInterface::class);
$file = $this->argument('file');
$configuration = $this->argument('configuration');
$user = $userRepository->find(intval($this->option('user')));
$cwd = getcwd();
$validTypes = config('import.options.file.import_formats');
$type = strtolower($this->option('type'));
if (null === $user) {
$this->error(sprintf('There is no user with ID %d.', $this->option('user')));
$file = $this->argument('file');
$configuration = $this->argument('configuration');
$cwd = getcwd();
$validTypes = config('import.options.file.import_formats');
$type = strtolower($this->option('type'));
return false;
}
if (!in_array($type, $validTypes)) {
$this->error(sprintf('Cannot import file of type "%s"', $type));
if (!\in_array($type, $validTypes, true)) {
$this->errorLine(sprintf('Cannot import file of type "%s"', $type));
return false;
}
if (!file_exists($file)) {
$this->error(sprintf('Firefly III cannot find file "%s" (working directory: "%s").', $file, $cwd));
$this->errorLine(sprintf('Firefly III cannot find file "%s" (working directory: "%s").', $file, $cwd));
return false;
}
if (!file_exists($configuration)) {
$this->error(sprintf('Firefly III cannot find configuration file "%s" (working directory: "%s").', $configuration, $cwd));
$this->errorLine(sprintf('Firefly III cannot find configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* EncryptFile.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,11 +19,11 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Services\Internal\File\EncryptService;
use Illuminate\Console\Command;
/**
@@ -44,31 +45,26 @@ class EncryptFile extends Command
*/
protected $signature = 'firefly:encrypt-file {file} {key}';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
public function handle()
public function handle(): int
{
$file = e(strval($this->argument('file')));
if (!file_exists($file)) {
$this->error(sprintf('File "%s" does not seem to exist.', $file));
$code = 0;
$file = (string)$this->argument('file');
$key = (string)$this->argument('key');
/** @var EncryptService $service */
$service = app(EncryptService::class);
return;
try {
$service->encrypt($file, $key);
} catch (FireflyException $e) {
$this->error($e->getMessage());
$code = 1;
}
$content = file_get_contents($file);
$content = Crypt::encrypt($content);
$newName = e(strval($this->argument('key'))) . '.upload';
$path = storage_path('upload') . '/' . $newName;
file_put_contents($path, $content);
$this->line(sprintf('Encrypted "%s" and put it in "%s"', $file, $path));
return $code;
}
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* Import.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,12 +19,10 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Import\Routine\RoutineInterface;
use FireflyIII\Models\ImportJob;
use Illuminate\Console\Command;
@@ -68,25 +67,21 @@ class Import extends Command
$jobKey = $this->argument('key');
$job = ImportJob::where('key', $jobKey)->first();
if (null === $job) {
$this->error(sprintf('No job found with key "%s"', $jobKey));
$this->errorLine(sprintf('No job found with key "%s"', $jobKey));
return;
}
if (!$this->isValid($job)) {
Log::error('Job is not valid for some reason. Exit.');
$this->errorLine('Job is not valid for some reason. Exit.');
return;
}
$this->line(sprintf('Going to import job with key "%s" of type "%s"', $job->key, $job->file_type));
$monolog = Log::getMonolog();
$handler = new CommandHandler($this);
$monolog->pushHandler($handler);
$this->infoLine(sprintf('Going to import job with key "%s" of type "%s"', $job->key, $job->file_type));
// actually start job:
$type = 'csv' === $job->file_type ? 'file' : $job->file_type;
$key = sprintf('import.routine.%s', $type);
$type = 'csv' === $job->file_type ? 'file' : $job->file_type;
$key = sprintf('import.routine.%s', $type);
$className = config($key);
if (null === $className || !class_exists($className)) {
throw new FireflyException(sprintf('Cannot find import routine class for job of type "%s".', $type)); // @codeCoverageIgnore
@@ -99,16 +94,37 @@ class Import extends Command
/** @var MessageBag $error */
foreach ($routine->getErrors() as $index => $error) {
$this->error(sprintf('Error importing line #%d: %s', $index, $error));
$this->errorLine(sprintf('Error importing line #%d: %s', $index, $error));
}
$this->line(
$this->infoLine(
sprintf('The import has finished. %d transactions have been imported out of %d records.', $routine->getJournals()->count(), $routine->getLines())
);
return;
}
/**
* @param string $message
* @param array|null $data
*/
private function errorLine(string $message, array $data = null): void
{
Log::error($message, $data ?? []);
$this->error($message);
}
/**
* @param string $message
* @param array $data
*/
private function infoLine(string $message, array $data = null): void
{
Log::info($message, $data ?? []);
$this->line($message);
}
/**
* Check if job is valid to be imported.
*
@@ -119,15 +135,14 @@ class Import extends Command
private function isValid(ImportJob $job): bool
{
if (null === $job) {
Log::error('This job does not seem to exist.');
$this->error('This job does not seem to exist.');
$this->errorLine('This job does not seem to exist.');
return false;
}
if ('configured' !== $job->status) {
Log::error(sprintf('This job is not ready to be imported (status is %s).', $job->status));
$this->error('This job is not ready to be imported.');
$this->errorLine('This job is not ready to be imported.');
return false;
}

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* UpgradeDatabase.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,7 +19,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -26,6 +26,7 @@ use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
@@ -86,6 +87,7 @@ class UpgradeDatabase extends Command
$this->updateOtherCurrencies();
$this->line('Done updating currency information..');
$this->migrateNotes();
$this->migrateAttachmentData();
$this->info('Firefly III database is up to date.');
return;
@@ -281,6 +283,38 @@ class UpgradeDatabase extends Command
}
}
/**
* Move the description of each attachment (when not NULL) to the notes or to a new note object
* for all attachments.
*/
private function migrateAttachmentData(): void
{
$attachments = Attachment::get();
/** @var Attachment $att */
foreach ($attachments as $att) {
// move description:
$description = strval($att->description);
if (strlen($description) > 0) {
// find or create note:
$note = $att->notes()->first();
if (is_null($note)) {
$note = new Note;
$note->noteable()->associate($att);
}
$note->text = $description;
$note->save();
// clear description:
$att->description = '';
$att->save();
Log::debug(sprintf('Migrated attachment #%s description to note #%d', $att->id, $note->id));
}
}
}
/**
* Move all the journal_meta notes to their note object counter parts.
*

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* UseEncryption.php
@@ -19,7 +20,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* VerifiesAccessToken.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,7 +19,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -49,11 +49,11 @@ trait VerifiesAccessToken
*/
protected function verifyAccessToken(): bool
{
$userId = intval($this->option('user'));
$token = strval($this->option('token'));
$userId = (int)$this->option('user');
$token = (string)$this->option('token');
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
$user = $repository->find($userId);
$user = $repository->findNull($userId);
if (null === $user) {
Log::error(sprintf('verifyAccessToken(): no such user for input "%d"', $userId));
@@ -68,7 +68,7 @@ trait VerifiesAccessToken
}
if (!($accessToken->data === $token)) {
Log::error(sprintf('Invalid access token for user #%d.', $userId));
Log::error(sprintf('Token given is "%s", expected "%s".', $token, $accessToken->data));
Log::error(sprintf('Token given is "%s", expected something else.', $token));
return false;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* RequestedVersionCheckStatus.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -19,7 +20,6 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Events;
@@ -49,4 +49,4 @@ class RequestedVersionCheckStatus extends Event
{
$this->user = $user;
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* StoredTransactionJournal.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,7 +19,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Events;
@@ -26,6 +26,7 @@ use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
/**
* @codeCoverageIgnore
* Class StoredTransactionJournal.
*/
class StoredTransactionJournal extends Event

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* UpdatedTransactionJournal.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,7 +19,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Events;
@@ -27,6 +27,9 @@ use Illuminate\Queue\SerializesModels;
/**
* Class UpdatedTransactionJournal.
*
* @codeCoverageIgnore
*
*/
class UpdatedTransactionJournal extends Event
{

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* FireflyException.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,13 +19,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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Exceptions;
use Exception;
/**
* Class FireflyException.
*/
class FireflyException extends \Exception
class FireflyException extends Exception
{
}

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* Handler.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,15 +19,17 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Exceptions;
use ErrorException;
use Exception;
use FireflyIII\Jobs\MailError;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Handler
@@ -62,6 +65,37 @@ class Handler extends ExceptionHandler
*/
public function render($request, Exception $exception)
{
if ($exception instanceof ValidationException && $request->expectsJson()) {
// ignore it: controller will handle it.
return parent::render($request, $exception);
}
if ($exception instanceof NotFoundHttpException && $request->expectsJson()) {
// JSON error:
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
}
if ($exception instanceof AuthenticationException && $request->expectsJson()) {
// somehow Laravel handler does not catch this:
return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401);
}
if ($request->expectsJson()) {
$isDebug = config('app.debug', false);
if ($isDebug) {
return response()->json(
[
'message' => $exception->getMessage(),
'exception' => get_class($exception),
'line' => $exception->getLine(),
'file' => $exception->getFile(),
'trace' => $exception->getTrace(),
], 500
);
}
return response()->json(['message' => 'Internal Firefly III Exception. See log files.', 'exception' => get_class($exception)], 500);
}
if ($exception instanceof FireflyException || $exception instanceof ErrorException) {
$isDebug = env('APP_DEBUG', false);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* UploadCollector.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,13 +19,12 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Export\Collector;
use Crypt;
use Exception;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Log;
use Storage;
@@ -99,7 +99,7 @@ class UploadCollector extends BasicCollector implements CollectorInterface
$content = '';
try {
$content = Crypt::decrypt($this->uploadDisk->get(sprintf('%s.upload', $key)));
} catch (FileNotFoundException | DecryptException $e) {
} catch (Exception | DecryptException $e) {
Log::error(sprintf('Could not decrypt old import file "%s". Skipped because: %s', $key, $e->getMessage()));
}

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* ExpandedProcessor.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -18,7 +19,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Export;
@@ -124,7 +124,7 @@ class ExpandedProcessor implements ProcessorInterface
$currencyId = $ibans[$accountId]['currency_id'] ?? 0;
$opposingCurrencyId = $ibans[$opposingId]['currency_id'] ?? 0;
$transaction->notes = $notes[$journalId] ?? '';
$transaction->tags = join(',', $tags[$journalId] ?? []);
$transaction->tags = implode(',', $tags[$journalId] ?? []);
$transaction->account_number = $ibans[$accountId]['accountNumber'] ?? '';
$transaction->account_bic = $ibans[$accountId]['BIC'] ?? '';
$transaction->account_currency_code = $currencies[$currencyId] ?? '';
@@ -331,6 +331,7 @@ class ExpandedProcessor implements ProcessorInterface
* @param array $array
*
* @return array
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
private function getTags(array $array): array
{

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,179 @@
<?php
declare(strict_types=1);
/**
* AccountFactory.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\Factory;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Services\Internal\Support\AccountServiceTrait;
use FireflyIII\User;
/**
* Factory to create or return accounts.
*
* Class AccountFactory
*/
class AccountFactory
{
use AccountServiceTrait;
/** @var User */
private $user;
/**
* @param array $data
*
* @return Account
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function create(array $data): Account
{
$type = $this->getAccountType($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;
}
// create it:
$databaseData
= [
'user_id' => $this->user->id,
'account_type_id' => $type->id,
'name' => $data['name'],
'virtual_balance' => strlen(strval($data['virtualBalance'])) === 0 ? '0' : $data['virtualBalance'],
'active' => true === $data['active'] ? true : false,
'iban' => $data['iban'],
];
// remove virtual balance when not an asset account:
if ($type->type !== AccountType::ASSET) {
$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;
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account|null
*/
public function find(string $accountName, string $accountType): ?Account
{
$type = AccountType::whereType($accountType)->first();
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(['accounts.*']);
/** @var Account $object */
foreach ($accounts as $object) {
if ($object->name === $accountName) {
return $object;
}
}
return null;
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account
* @throws \FireflyIII\Exceptions\FireflyException
* @throws \FireflyIII\Exceptions\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.*']);
/** @var Account $object */
foreach ($accounts as $object) {
if ($object->name === $accountName) {
return $object;
}
}
return $this->create(
[
'user_id' => $this->user->id,
'name' => $accountName,
'account_type_id' => $type->id,
'accountType' => null,
'virtualBalance' => '0',
'iban' => null,
'active' => true,
]
);
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @param int|null $accountTypeId
* @param null|string $accountType
*
* @return AccountType|null
*/
protected function getAccountType(?int $accountTypeId, ?string $accountType): ?AccountType
{
$accountTypeId = intval($accountTypeId);
if ($accountTypeId > 0) {
return AccountType::find($accountTypeId);
}
$type = config('firefly.accountTypeByIdentifier.' . strval($accountType));
$result = AccountType::whereType($type)->first();
if (is_null($result) && !is_null($accountType)) {
// try as full name:
$result = AccountType::whereType($accountType)->first();
}
return $result;
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/**
* AccountMetaFactory.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\Factory;
use FireflyIII\Models\AccountMeta;
/**
* Class AccountMetaFactory
*/
class AccountMetaFactory
{
/**
* @param array $data
*
* @return AccountMeta|null
*/
public function create(array $data): ?AccountMeta
{
return AccountMeta::create($data);
}
}

137
app/Factory/BillFactory.php Normal file
View File

@@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
/**
* BillFactory.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\Factory;
use FireflyIII\Models\Bill;
use FireflyIII\Services\Internal\Support\BillServiceTrait;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
* Class BillFactory
*/
class BillFactory
{
use BillServiceTrait;
/** @var User */
private $user;
/**
* @param array $data
*
* @return Bill|null
*/
public function create(array $data): ?Bill
{
$matchArray = explode(',', $data['match']);
$matchArray = array_unique($matchArray);
$match = join(',', $matchArray);
/** @var Bill $bill */
$bill = Bill::create(
[
'name' => $data['name'],
'match' => $match,
'amount_min' => $data['amount_min'],
'user_id' => $this->user->id,
'amount_max' => $data['amount_max'],
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
'skip' => $data['skip'],
'automatch' => $data['automatch'],
'active' => $data['active'],
]
);
// update note:
if (isset($data['notes'])) {
$this->updateNote($bill, $data['notes']);
}
return $bill;
}
/**
* @param int|null $billId
* @param null|string $billName
*
* @return Bill|null
*/
public function find(?int $billId, ?string $billName): ?Bill
{
$billId = intval($billId);
$billName = strval($billName);
// first find by ID:
if ($billId > 0) {
/** @var Bill $bill */
$bill = $this->user->bills()->find($billId);
if (!is_null($bill)) {
return $bill;
}
}
// then find by name:
if (strlen($billName) > 0) {
$bill = $this->findByName($billName);
if (!is_null($bill)) {
return $bill;
}
}
return null;
}
/**
* @param string $name
*
* @return Bill|null
*/
public function findByName(string $name): ?Bill
{
/** @var Collection $collection */
$collection = $this->user->bills()->get();
/** @var Bill $bill */
foreach ($collection as $bill) {
Log::debug(sprintf('"%s" vs. "%s"', $bill->name, $name));
if ($bill->name === $name) {
return $bill;
}
}
Log::debug(sprintf('Bill::Find by name returns NULL based on "%s"', $name));
return null;
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
}

View File

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
/**
* BudgetFactory.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\Factory;
use FireflyIII\Models\Budget;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Class BudgetFactory
*/
class BudgetFactory
{
/** @var User */
private $user;
/**
* @param int|null $budgetId
* @param null|string $budgetName
*
* @return Budget|null
*/
public function find(?int $budgetId, ?string $budgetName): ?Budget
{
$budgetId = intval($budgetId);
$budgetName = strval($budgetName);
if (strlen($budgetName) === 0 && $budgetId === 0) {
return null;
}
// first by ID:
if ($budgetId > 0) {
/** @var Budget $budget */
$budget = $this->user->budgets()->find($budgetId);
if (!is_null($budget)) {
return $budget;
}
}
if (strlen($budgetName) > 0) {
$budget = $this->findByName($budgetName);
if (!is_null($budget)) {
return $budget;
}
}
return null;
}
/**
* @param string $name
*
* @return Budget|null
*/
public function findByName(string $name): ?Budget
{
/** @var Collection $collection */
$collection = $this->user->budgets()->get();
/** @var Budget $budget */
foreach ($collection as $budget) {
if ($budget->name === $name) {
return $budget;
}
}
return null;
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
}

View File

@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
/**
* CategoryFactory.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\Factory;
use FireflyIII\Models\Category;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
* Class CategoryFactory
*/
class CategoryFactory
{
/** @var User */
private $user;
/**
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
/** @var Collection $collection */
$collection = $this->user->categories()->get();
/** @var Category $category */
foreach ($collection as $category) {
if ($category->name === $name) {
return $category;
}
}
return null;
}
/**
* @param int|null $categoryId
* @param null|string $categoryName
*
* @return Category|null
*/
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
{
$categoryId = intval($categoryId);
$categoryName = strval($categoryName);
Log::debug(sprintf('Going to find category with ID %d and name "%s"', $categoryId, $categoryName));
if (strlen($categoryName) === 0 && $categoryId === 0) {
return null;
}
// first by ID:
if ($categoryId > 0) {
/** @var Category $category */
$category = $this->user->categories()->find($categoryId);
if (!is_null($category)) {
return $category;
}
}
if (strlen($categoryName) > 0) {
$category = $this->findByName($categoryName);
if (!is_null($category)) {
return $category;
}
return Category::create(
[
'user_id' => $this->user->id,
'name' => $categoryName,
]
);
}
return null;
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
}

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
/**
* PiggyBankEventFactory.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\Factory;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Log;
/**
* Create piggy bank events.
*
* Class PiggyBankEventFactory
*/
class PiggyBankEventFactory
{
/**
* @param TransactionJournal $journal
* @param PiggyBank|null $piggyBank
*
* @return PiggyBankEvent|null
*/
public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): ?PiggyBankEvent
{
Log::debug(sprintf('Now in PiggyBankEventCreate for a %s', $journal->transactionType->type));
if (is_null($piggyBank)) {
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));
return null;
}
/** @var PiggyBankRepositoryInterface $piggyRepos */
$piggyRepos = app(PiggyBankRepositoryInterface::class);
$piggyRepos->setUser($journal->user);
// repetition exists?
$repetition = $piggyRepos->getRepetition($piggyBank, $journal->date);
if (null === $repetition->id) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
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.');
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

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
/**
* PiggyBankFactory.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\Factory;
use FireflyIII\Models\PiggyBank;
use FireflyIII\User;
/**
* Class PiggyBankFactory
*/
class PiggyBankFactory
{
/** @var User */
private $user;
/**
* @param int|null $piggyBankId
* @param null|string $piggyBankName
*
* @return PiggyBank|null
*/
public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank
{
$piggyBankId = intval($piggyBankId);
$piggyBankName = strval($piggyBankName);
if (strlen($piggyBankName) === 0 && $piggyBankId === 0) {
return null;
}
// first find by ID:
if ($piggyBankId > 0) {
/** @var PiggyBank $piggyBank */
$piggyBank = $this->user->piggyBanks()->find($piggyBankId);
if (!is_null($piggyBank)) {
return $piggyBank;
}
}
// then find by name:
if (strlen($piggyBankName) > 0) {
/** @var PiggyBank $piggyBank */
$piggyBank = $this->findByName($piggyBankName);
if (!is_null($piggyBank)) {
return $piggyBank;
}
}
return null;
}
/**
* @param string $name
*
* @return PiggyBank|null
*/
public function findByName(string $name): ?PiggyBank
{
$set = $this->user->piggyBanks()->get();
/** @var PiggyBank $piggy */
foreach ($set as $piggy) {
if ($piggy->name === $name) {
return $piggy;
}
}
return null;
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
}

102
app/Factory/TagFactory.php Normal file
View File

@@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
/**
* TagFactory.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\Factory;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Class TagFactory
*/
class TagFactory
{
/** @var Collection */
private $tags;
/** @var User */
private $user;
/**
* @param array $data
*
* @return Tag|null
*/
public function create(array $data): ?Tag
{
return Tag::create(
[
'user_id' => $this->user->id,
'tag' => $data['tag'],
'tagMode' => 'nothing',
'date' => $data['date'],
'description' => $data['description'],
'latitude' => $data['latitude'],
'longitude ' => $data['longitude'],
'zoomLevel' => $data['zoom_level'],
]
);
}
/**
* @param string $tag
*
* @return Tag|null
*/
public function findOrCreate(string $tag): ?Tag
{
if (is_null($this->tags)) {
$this->tags = $this->user->tags()->get();
}
/** @var Tag $object */
foreach ($this->tags as $object) {
if ($object->tag === $tag) {
return $object;
}
}
$newTag = $this->create(
[
'tag' => $tag,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoom_level' => null,
]
);
$this->tags->push($newTag);
return $newTag;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
}

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
/**
* TransactionCurrencyFactory.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\Factory;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Database\QueryException;
use Log;
/**
* Class TransactionCurrencyFactory
*/
class TransactionCurrencyFactory
{
/**
* @param array $data
*
* @return TransactionCurrency|null
*/
public function create(array $data): ?TransactionCurrency
{
$result = null;
try {
/** @var TransactionCurrency $currency */
$result = TransactionCurrency::create(
[
'name' => $data['name'],
'code' => $data['code'],
'symbol' => $data['symbol'],
'decimal_places' => $data['decimal_places'],
]
);
} catch (QueryException $e) {
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
}
return $result;
}
/**
* @param int|null $currencyId
* @param null|string $currencyCode
*
* @return TransactionCurrency|null
*/
public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{
$currencyCode = strval($currencyCode);
$currencyId = intval($currencyId);
if (strlen($currencyCode) === 0 && intval($currencyId) === 0) {
return null;
}
// first by ID:
if ($currencyId > 0) {
$currency = TransactionCurrency::find($currencyId);
if (!is_null($currency)) {
return $currency;
}
}
// then by code:
if (strlen($currencyCode) > 0) {
$currency = TransactionCurrency::whereCode($currencyCode)->first();
if (!is_null($currency)) {
return $currency;
}
}
return null;
}
}

View File

@@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
/**
* TransactionFactory.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\Factory;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Services\Internal\Support\TransactionServiceTrait;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Class TransactionFactory
*/
class TransactionFactory
{
use TransactionServiceTrait;
/** @var User */
private $user;
/**
* @param array $data
*
* @return Transaction
*/
public function create(array $data): Transaction
{
$currencyId = isset($data['currency']) ? $data['currency']->id : $data['currency_id'];
return Transaction::create(
[
'reconciled' => $data['reconciled'],
'account_id' => $data['account']->id,
'transaction_journal_id' => $data['transaction_journal']->id,
'description' => $data['description'],
'transaction_currency_id' => $currencyId,
'amount' => $data['amount'],
'foreign_amount' => $data['foreign_amount'],
'foreign_currency_id' => null,
'identifier' => $data['identifier'],
]
);
}
/**
* Create a pair of transactions based on the data given in the array.
*
* @param TransactionJournal $journal
* @param array $data
*
* @return Collection
*/
public function createPair(TransactionJournal $journal, array $data): Collection
{
// all this data is the same for both transactions:
$currency = $this->findCurrency($data['currency_id'], $data['currency_code']);
$description = $journal->description === $data['description'] ? null : $data['description'];
// type of source account depends on journal type:
$sourceType = $this->accountType($journal, 'source');
$sourceAccount = $this->findAccount($sourceType, $data['source_id'], $data['source_name']);
// same for destination account:
$destinationType = $this->accountType($journal, 'destination');
$destinationAccount = $this->findAccount($destinationType, $data['destination_id'], $data['destination_name']);
// first make a "negative" (source) transaction based on the data in the array.
$source = $this->create(
[
'description' => $description,
'amount' => app('steam')->negative(strval($data['amount'])),
'foreign_amount' => null,
'currency' => $currency,
'account' => $sourceAccount,
'transaction_journal' => $journal,
'reconciled' => $data['reconciled'],
'identifier' => $data['identifier'],
]
);
// then make a "positive" transaction based on the data in the array.
$dest = $this->create(
[
'description' => $description,
'amount' => app('steam')->positive(strval($data['amount'])),
'foreign_amount' => null,
'currency' => $currency,
'account' => $destinationAccount,
'transaction_journal' => $journal,
'reconciled' => $data['reconciled'],
'identifier' => $data['identifier'],
]
);
// set foreign currency
$foreign = $this->findCurrency($data['foreign_currency_id'], $data['foreign_currency_code']);
$this->setForeignCurrency($source, $foreign);
$this->setForeignCurrency($dest, $foreign);
// set foreign amount:
if (!is_null($data['foreign_amount'])) {
$this->setForeignAmount($source, app('steam')->negative(strval($data['foreign_amount'])));
$this->setForeignAmount($dest, app('steam')->positive(strval($data['foreign_amount'])));
}
// set budget:
if ($journal->transactionType->type === TransactionType::TRANSFER) {
$data['budget_id'] = null;
$data['budget_name'] = null;
}
$budget = $this->findBudget($data['budget_id'], $data['budget_name']);
$this->setBudget($source, $budget);
$this->setBudget($dest, $budget);
// set category
$category = $this->findCategory($data['category_id'], $data['category_name']);
$this->setCategory($source, $category);
$this->setCategory($dest, $category);
return new Collection([$source, $dest]);
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
}

View File

@@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
/**
* TransactionJournalFactory.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\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
use FireflyIII\User;
use Log;
/**
* Class TransactionJournalFactory
*/
class TransactionJournalFactory
{
use JournalServiceTrait;
/** @var User */
private $user;
/**
* Create a new transaction journal and associated transactions.
*
* @param array $data
*
* @return TransactionJournal
* @throws FireflyException
*/
public function create(array $data): TransactionJournal
{
Log::debug('Start of TransactionJournalFactory::create()');
// store basic journal first.
$type = $this->findTransactionType($data['type']);
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
$journal = TransactionJournal::create(
[
'user_id' => $data['user'],
'transaction_type_id' => $type->id,
'bill_id' => null,
'transaction_currency_id' => $defaultCurrency->id,
'description' => $data['description'],
'date' => $data['date']->format('Y-m-d'),
'order' => 0,
'tag_count' => 0,
'completed' => 0,
]
);
// store basic transactions:
/** @var TransactionFactory $factory */
$factory = app(TransactionFactory::class);
$factory->setUser($this->user);
/** @var array $trData */
foreach ($data['transactions'] as $trData) {
$factory->createPair($journal, $trData);
}
$journal->completed = true;
$journal->save();
// link bill:
$this->connectBill($journal, $data);
// link piggy bank (if transfer)
$this->connectPiggyBank($journal, $data);
// link tags:
$this->connectTags($journal, $data);
// store note:
$this->storeNote($journal, strval($data['notes']));
// store date meta fields (if present):
$fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
'due_date', 'payment_date', 'invoice_date', 'internal_reference','bunq_payment_id'];
foreach ($fields as $field) {
$this->storeMeta($journal, $data, $field);
}
Log::debug('End of TransactionJournalFactory::create()');
return $journal;
}
/**
* Set the user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @param TransactionJournal $journal
* @param array $data
*/
protected function connectPiggyBank(TransactionJournal $journal, array $data): void
{
/** @var PiggyBankFactory $factory */
$factory = app(PiggyBankFactory::class);
$factory->setUser($this->user);
$piggyBank = $factory->find($data['piggy_bank_id'], $data['piggy_bank_name']);
if (!is_null($piggyBank)) {
/** @var PiggyBankEventFactory $factory */
$factory = app(PiggyBankEventFactory::class);
$factory->create($journal, $piggyBank);
}
}
/**
* Get the transaction type. Since this is mandatory, will throw an exception when nothing comes up. Will always
* use TransactionType repository.
*
* @param string $type
*
* @return TransactionType
* @throws FireflyException
*/
protected function findTransactionType(string $type): TransactionType
{
$factory = app(TransactionTypeFactory::class);
$transactionType = $factory->find($type);
if (is_null($transactionType)) {
throw new FireflyException(sprintf('Could not find transaction type for "%s"', $type)); // @codeCoverageIgnore
}
return $transactionType;
}
}

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
/**
* TransactionJournalMetaFactory.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\Factory;
use Carbon\Carbon;
use Exception;
use FireflyIII\Models\TransactionJournalMeta;
use Log;
/**
* Class TransactionJournalMetaFactory
*/
class TransactionJournalMetaFactory
{
/**
* @param array $data
*
* @return TransactionJournalMeta|null
*/
public function updateOrCreate(array $data): ?TransactionJournalMeta
{
$value = $data['data'];
/** @var TransactionJournalMeta $entry */
$entry = $data['journal']->transactionJournalMeta()->where('name', $data['name'])->first();
if (null === $value && null !== $entry) {
try {
$entry->delete();
} catch (Exception $e) { // @codeCoverageIgnore
Log::error(sprintf('Could not delete transaction journal meta: %s', $e->getMessage())); // @codeCoverageIgnore
}
return null;
}
if ($data['data'] instanceof Carbon) {
$value = $data['data']->toW3cString();
}
if ((string)$value === '') {
// don't store blank strings.
if (null !== $entry) {
try {
$entry->delete();
} catch (Exception $e) { // @codeCoverageIgnore
Log::error(sprintf('Could not delete transaction journal meta: %s', $e->getMessage())); // @codeCoverageIgnore
}
}
return null;
}
if (null === $entry) {
$entry = new TransactionJournalMeta();
$entry->transactionJournal()->associate($data['journal']);
$entry->name = $data['name'];
}
$entry->data = $value;
$entry->save();
return $entry;
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
/**
* TransactionTypeFactory.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\Factory;
use FireflyIII\Models\TransactionType;
/**
* @codeCoverageIgnore
* Class TransactionTypeFactory
*/
class TransactionTypeFactory
{
/**
* @param string $type
*
* @return TransactionType|null
*/
public function find(string $type): ?TransactionType
{
return TransactionType::whereType(ucfirst($type))->first();
}
}

View File

@@ -45,6 +45,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
/**
* @return string
* @throws \Throwable
*/
public function generate(): string
{

View File

@@ -63,6 +63,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
/**
* @return string
* @throws \Throwable
*/
public function generate(): string
{

View File

@@ -64,6 +64,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
/**
* @return string
* @throws \Throwable
*/
public function generate(): string
{

View File

@@ -146,15 +146,12 @@ class Support
*/
protected function summarizeByAccount(Collection $collection): array
{
$result = [
'sum' => '0',
];
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
$accountId = $transaction->account_id;
$result[$accountId] = $result[$accountId] ?? '0';
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
$result['sum'] = bcadd($result['sum'], $transaction->transaction_amount);
}
return $result;

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\AdminRequestedTestMessage;
use FireflyIII\Mail\AdminTestMail;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Log;
use Mail;
use Session;
@@ -43,6 +44,15 @@ class AdminEventHandler
*/
public function sendTestMessage(AdminRequestedTestMessage $event): bool
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
// is user even admin?
if (!$repository->hasRole($event->user, 'owner')) {
return true;
}
$email = $event->user->email;
$ipAddress = $event->ipAddress;

View File

@@ -30,7 +30,6 @@ use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface as PRI;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface as RGRI;
use FireflyIII\Support\Events\BillScanner;
use FireflyIII\TransactionRules\Processor;
use Log;
/**
* @codeCoverageIgnore
@@ -61,67 +60,13 @@ class StoredJournalEventHandler
$this->ruleGroupRepository = $ruleGroupRepository;
}
/**
* This method connects a new transfer to a piggy bank.
*
* @param StoredTransactionJournal $event
*
* @return bool
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function connectToPiggyBank(StoredTransactionJournal $event): bool
{
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
$piggyBank = $this->repository->find($piggyBankId);
// is a transfer?
if (!$this->journalRepository->isTransfer($journal)) {
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
return true;
}
// piggy exists?
if (null === $piggyBank->id) {
Log::error(sprintf('There is no piggy bank with ID #%d', $piggyBankId));
return true;
}
// repetition exists?
$repetition = $this->repository->getRepetition($piggyBank, $journal->date);
if (null === $repetition->id) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
return true;
}
// get the amount
$amount = $this->repository->getExactAmount($piggyBank, $repetition, $journal);
if (0 === bccomp($amount, '0')) {
Log::debug('Amount is zero, will not create event.');
return true;
}
// update amount
$this->repository->addAmountToRepetition($repetition, $amount);
$event = $this->repository->createEventWithJournal($piggyBank, $amount, $journal);
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
return true;
}
/**
* This method grabs all the users rules and processes them.
*
* @param StoredTransactionJournal $storedJournalEvent
*
* @return bool
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function processRules(StoredTransactionJournal $storedJournalEvent): bool
{

View File

@@ -55,6 +55,7 @@ class UpdatedJournalEventHandler
* @param UpdatedTransactionJournal $updatedJournalEvent
*
* @return bool
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function processRules(UpdatedTransactionJournal $updatedJournalEvent): bool
{

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Events;
use FireflyConfig;
use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Services\Github\Object\Release;
use FireflyIII\Services\Github\Request\UpdateRequest;
use FireflyIII\User;
@@ -43,22 +44,26 @@ class VersionCheckEventHandler
public function checkForUpdates(RequestedVersionCheckStatus $event)
{
// in Sandstorm, cannot check for updates:
$sandstorm = 1 === intval(getenv('SANDSTORM'));
$sandstorm = 1 === (int)getenv('SANDSTORM');
if ($sandstorm === true) {
return;
return; // @codeCoverageIgnore
}
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
/** @var User $user */
$user = $event->user;
if (!$user->hasRole('owner')) {
if (!$repository->hasRole($user, 'owner')) {
return;
}
$permission = FireflyConfig::get('permission_update_check', -1);
$lastCheckTime = FireflyConfig::get('last_update_check', time());
$now = time();
if ($now - $lastCheckTime->data < 604800) {
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Difference is %d seconds.', $diff));
if ($diff < 604800) {
Log::debug(sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
return;
@@ -70,7 +75,7 @@ class VersionCheckEventHandler
// have actual permission?
if ($permission->data === -1) {
// never asked before.
session()->flash('info', strval(trans('firefly.check_for_updates_permission', ['link' => route('admin.update-check')])));
session()->flash('info', (string)trans('firefly.check_for_updates_permission', ['link' => route('admin.update-check')]));
return;
}
@@ -79,7 +84,7 @@ class VersionCheckEventHandler
/** @var UpdateRequest $request */
$request = app(UpdateRequest::class);
$check = -2;
$first = new Release(['id' => '0', 'title' => '0', 'updated' => '2017-01-01', 'content' => '']);
$first = new Release(['id' => '0', 'title' => '0.2', 'updated' => '2017-01-01', 'content' => '']);
try {
$request->call();
$releases = $request->getReleases();
@@ -87,6 +92,7 @@ class VersionCheckEventHandler
/** @var Release $first */
$first = reset($releases);
$check = version_compare($current, $first->getTitle());
Log::debug(sprintf('Comparing %s with %s, result is %s', $current, $first->getTitle(), $check));
FireflyConfig::set('last_update_check', time());
} catch (FireflyException $e) {
Log::error(sprintf('Could not check for updates: %s', $e->getMessage()));
@@ -98,19 +104,19 @@ class VersionCheckEventHandler
if ($check === -1) {
// there is a new FF version!
$monthAndDayFormat = (string)trans('config.month_and_day');
$string = strval(
trans(
'firefly.update_new_version_alert',
['your_version' => $current, 'new_version' => $first->getTitle(), 'date' => $first->getUpdated()->formatLocalized($monthAndDayFormat)]
)
$string = (string)trans(
'firefly.update_new_version_alert',
[
'your_version' => $current,
'new_version' => $first->getTitle(),
'date' => $first->getUpdated()->formatLocalized($monthAndDayFormat),
]
);
}
if ($check !== 0) {
// flash info
session()->flash('info', $string);
}
return;
}
}
}

View File

@@ -50,8 +50,9 @@ class AttachmentHelper implements AttachmentHelperInterface
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
protected $uploadDisk;
/**
*
* AttachmentHelper constructor.
*/
public function __construct()
{
@@ -154,6 +155,7 @@ class AttachmentHelper implements AttachmentHelperInterface
* @param Model $model
*
* @return Attachment
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
protected function processFile(UploadedFile $file, Model $model): Attachment
{
@@ -205,7 +207,7 @@ class AttachmentHelper implements AttachmentHelperInterface
Log::debug('Now in validMime()');
$mime = e($file->getMimeType());
$name = e($file->getClientOriginalName());
Log::debug(sprintf('Name is %, and mime is %s', $name, $mime));
Log::debug(sprintf('Name is %s, and mime is %s', $name, $mime));
Log::debug('Valid mimes are', $this->allowedMimes);
if (!in_array($mime, $this->allowedMimes)) {

View File

@@ -79,6 +79,9 @@ class MetaPieChart implements MetaPieChartInterface
/** @var User */
protected $user;
/**
* MetaPieChart constructor.
*/
public function __construct()
{
$this->accounts = new Collection;
@@ -273,12 +276,15 @@ class MetaPieChart implements MetaPieChartInterface
$collector->setBudgets($this->budgets);
$collector->setCategories($this->categories);
// @codeCoverageIgnoreStart
if ($this->tags->count() > 0) {
$collector->setTags($this->tags);
$collector->withCategoryInformation();
$collector->withBudgetInformation();
}
// @codeCoverageIgnoreEnd
return $collector->getJournals();
}
@@ -294,7 +300,7 @@ class MetaPieChart implements MetaPieChartInterface
{
if (0 === count($fields) && $this->tags->count() > 0) {
// do a special group on tags:
return $this->groupByTag($set);
return $this->groupByTag($set); // @codeCoverageIgnore
}
$grouped = [];
@@ -338,6 +344,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Collection $set
*
* @return array

View File

@@ -35,15 +35,15 @@ class BalanceLine
/**
*
*/
const ROLE_DEFAULTROLE = 1;
public const ROLE_DEFAULTROLE = 1;
/**
*
*/
const ROLE_TAGROLE = 2;
public const ROLE_TAGROLE = 2;
/**
*
*/
const ROLE_DIFFROLE = 3;
public const ROLE_DIFFROLE = 3;
/** @var Collection */
protected $balanceEntries;

View File

@@ -25,11 +25,13 @@ namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Filter\CountAttachmentsFilter;
use FireflyIII\Helpers\Filter\FilterInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\SplitIndicatorFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
@@ -69,6 +71,8 @@ class JournalCollector implements JournalCollectorInterface
'transaction_journals.description',
'transaction_journals.date',
'transaction_journals.encrypted',
'transaction_journals.created_at',
'transaction_journals.updated_at',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'transaction_journals.updated_at',
@@ -252,6 +256,7 @@ class JournalCollector implements JournalCollectorInterface
$cache->addProperty($key);
if ($cache->has()) {
Log::debug(sprintf('Return cache of query with ID "%s".', $key));
return $cache->get(); // @codeCoverageIgnore
}
@@ -270,10 +275,19 @@ class JournalCollector implements JournalCollectorInterface
if (null !== $transaction->bill_name) {
$transaction->bill_name = Steam::decrypt(intval($transaction->bill_name_encrypted), $transaction->bill_name);
}
$transaction->account_name = app('steam')->tryDecrypt($transaction->account_name);
$transaction->opposing_account_name = app('steam')->tryDecrypt($transaction->opposing_account_name);
$transaction->account_iban = app('steam')->tryDecrypt($transaction->account_iban);
$transaction->opposing_account_iban = app('steam')->tryDecrypt($transaction->opposing_account_iban);
// budget name
$transaction->transaction_journal_budget_name = app('steam')->tryDecrypt($transaction->transaction_journal_budget_name);
$transaction->transaction_budget_name = app('steam')->tryDecrypt($transaction->transaction_budget_name);
// category name:
$transaction->transaction_journal_category_name = app('steam')->tryDecrypt($transaction->transaction_journal_category_name);
$transaction->transaction_category_name = app('steam')->tryDecrypt($transaction->transaction_category_name);
}
);
Log::debug(sprintf('Cached query with ID "%s".', $key));
$cache->store($set);
@@ -342,7 +356,7 @@ class JournalCollector implements JournalCollectorInterface
*/
public function setAfter(Carbon $after): JournalCollectorInterface
{
$afterStr = $after->format('Y-m-d');
$afterStr = $after->format('Y-m-d 00:00:00');
$this->query->where('transaction_journals.date', '>=', $afterStr);
Log::debug(sprintf('JournalCollector range is now after %s (inclusive)', $afterStr));
@@ -378,7 +392,7 @@ class JournalCollector implements JournalCollectorInterface
*/
public function setBefore(Carbon $before): JournalCollectorInterface
{
$beforeStr = $before->format('Y-m-d');
$beforeStr = $before->format('Y-m-d 00:00:00');
$this->query->where('transaction_journals.date', '<=', $beforeStr);
Log::debug(sprintf('JournalCollector range is now before %s (inclusive)', $beforeStr));
@@ -485,6 +499,23 @@ class JournalCollector implements JournalCollectorInterface
return $this;
}
/**
* @param Collection $journals
*
* @return JournalCollectorInterface
*/
public function setJournals(Collection $journals): JournalCollectorInterface
{
$ids = $journals->pluck('id')->toArray();
$this->query->where(
function (EloquentBuilder $q) use ($ids) {
$q->whereIn('transaction_journals.id', $ids);
}
);
return $this;
}
/**
* @param int $limit
*
@@ -565,8 +596,8 @@ class JournalCollector implements JournalCollectorInterface
public function setRange(Carbon $start, Carbon $end): JournalCollectorInterface
{
if ($start <= $end) {
$startStr = $start->format('Y-m-d');
$endStr = $end->format('Y-m-d');
$startStr = $start->format('Y-m-d 00:00:00');
$endStr = $end->format('Y-m-d 23:59:59');
$this->query->where('transaction_journals.date', '>=', $startStr);
$this->query->where('transaction_journals.date', '<=', $endStr);
Log::debug(sprintf('JournalCollector range is now %s - %s (inclusive)', $startStr, $endStr));
@@ -731,6 +762,8 @@ class JournalCollector implements JournalCollectorInterface
TransferFilter::class => new TransferFilter,
PositiveAmountFilter::class => new PositiveAmountFilter,
NegativeAmountFilter::class => new NegativeAmountFilter,
SplitIndicatorFilter::class => new SplitIndicatorFilter,
CountAttachmentsFilter::class => new CountAttachmentsFilter,
];
Log::debug(sprintf('Will run %d filters on the set.', count($this->filters)));
foreach ($this->filters as $enabled) {
@@ -801,6 +834,7 @@ class JournalCollector implements JournalCollectorInterface
/**
*
* @throws \InvalidArgumentException
*/
private function joinOpposingTables()
{

View File

@@ -27,7 +27,6 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@@ -147,6 +146,13 @@ interface JournalCollectorInterface
*/
public function setCategory(Category $category): JournalCollectorInterface;
/**
* @param Collection $journals
*
* @return JournalCollectorInterface
*/
public function setJournals(Collection $journals): JournalCollectorInterface;
/**
* @param int $limit
*

View File

@@ -0,0 +1,67 @@
<?php
/**
* CountAttachmentsFilter.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Filter;
use DB;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection;
/**
* Class CountAttachmentsFilter
*/
class CountAttachmentsFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
// grab journal ID's:
$ids = $set->pluck('journal_id')->toArray();
$result = DB::table('attachments')
->whereNull('deleted_at')
->whereIn('attachable_id', $ids)
->where('attachable_type', TransactionJournal::class)
->groupBy('attachable_id')->get(['attachable_id', DB::raw('COUNT(*) as number')]);
$counter = [];
foreach ($result as $row) {
$counter[$row->attachable_id] = $row->number;
}
$set->each(
function (Transaction $transaction) use ($counter) {
$id = (int)$transaction->journal_id;
$count = $counter[$id] ?? 0;
$transaction->attachmentCount = $count;
}
);
return $set;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* SplitIndicatorFilter.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Filter;
use DB;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
/**
* Class SplitIndicatorFilter
*/
class SplitIndicatorFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
// grab journal ID's:
$ids = $set->pluck('journal_id')->toArray();
$result = DB::table('transactions')
->whereNull('deleted_at')->whereIn('transaction_journal_id', $ids)
->groupBy('transaction_journal_id')->get(['transaction_journal_id', DB::raw('COUNT(*) as number')]);
$counter = [];
foreach ($result as $row) {
$counter[$row->transaction_journal_id] = $row->number;
}
$set->each(
function (Transaction $transaction) use ($counter) {
$id = (int)$transaction->journal_id;
$count = $counter[$id] ?? 0;
$transaction->is_split = false;
if ($count > 2) {
$transaction->is_split = true;
}
}
);
return $set;
}
}

View File

@@ -37,7 +37,7 @@ class Help implements HelpInterface
/**
*
*/
const CACHEKEY = 'help_%s_%s';
public const CACHEKEY = 'help_%s_%s';
/** @var string */
protected $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36';

View File

@@ -28,6 +28,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
/**
@@ -56,11 +57,8 @@ class PopupReport implements PopupReportInterface
return $journals->filter(
function (Transaction $transaction) {
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
if (0 === $tags) {
return true;
}
return false;
return 0 === $tags;
}
);
}
@@ -182,6 +180,9 @@ class PopupReport implements PopupReportInterface
*/
public function byIncome(Account $account, array $attributes): Collection
{
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($account->user);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
@@ -191,9 +192,10 @@ class PopupReport implements PopupReportInterface
// filter the set so the destinations outside of $attributes['accounts'] are not included.
$journals = $journals->filter(
function (Transaction $transaction) use ($report) {
function (Transaction $transaction) use ($report, $repository) {
// get the destinations:
$destinations = $transaction->transactionJournal->destinationAccountList()->pluck('id')->toArray();
$journal = $transaction->transactionJournal;
$destinations = $repository->getJournalDestinationAccounts($journal)->pluck('id')->toArray();
// do these intersect with the current list?
return !empty(array_intersect($report, $destinations));

View File

@@ -119,6 +119,7 @@ class ReportHelper implements ReportHelperInterface
* @param Carbon $date
*
* @return array
* @throws \InvalidArgumentException
*/
public function listOfMonths(Carbon $date): array
{

View File

@@ -26,7 +26,8 @@ use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\ReconciliationFormRequest;
use FireflyIII\Http\Requests\ReconciliationStoreRequest;
use FireflyIII\Http\Requests\ReconciliationUpdateRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
@@ -35,10 +36,11 @@ use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
use Preferences;
use Response;
use Session;
/**
@@ -48,6 +50,13 @@ use Session;
*/
class ReconcileController extends Controller
{
/** @var CurrencyUpdateService */
private $accountRepos;
/** @var AccountRepositoryInterface */
private $currencyRepos;
/** @var JournalRepositoryInterface */
private $repository;
/**
*
*/
@@ -60,6 +69,9 @@ class ReconcileController extends Controller
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-credit-card');
app('view')->share('title', trans('firefly.accounts'));
$this->repository = app(JournalRepositoryInterface::class);
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
return $next($request);
}
@@ -80,11 +92,11 @@ class ReconcileController extends Controller
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
// journal related code
$pTransaction = $journal->positiveTransaction();
$pTransaction = $this->repository->getFirstPosTransaction($journal);
$preFilled = [
'date' => $journal->dateAsString(),
'category' => $journal->categoryAsString(),
'tags' => join(',', $journal->tags->pluck('tag')->toArray()),
'date' => $this->repository->getJournalDate($journal, null),
'category' => $this->repository->getJournalCategoryName($journal),
'tags' => implode(',', $journal->tags->pluck('tag')->toArray()),
'amount' => $pTransaction->amount,
];
@@ -126,10 +138,8 @@ class ReconcileController extends Controller
$clearedAmount = '0';
$route = route('accounts.reconcile.submit', [$account->id, $start->format('Ymd'), $end->format('Ymd')]);
// get sum of transaction amounts:
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$transactions = $repository->getTransactionsById($transactionIds);
$cleared = $repository->getTransactionsById($clearedIds);
$transactions = $this->repository->getTransactionsById($transactionIds);
$cleared = $this->repository->getTransactionsById($clearedIds);
$countCleared = 0;
/** @var Transaction $transaction */
@@ -157,7 +167,7 @@ class ReconcileController extends Controller
)->render(),
];
return Response::json($return);
return response()->json($return);
}
/**
@@ -179,10 +189,8 @@ class ReconcileController extends Controller
return redirect(route('accounts.index', [config('firefly.shortNamesByFullName.' . $account->accountType->type)]));
}
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencyId = intval($account->getMeta('currency_id'));
$currency = $currencyRepos->find($currencyId);
$currencyId = intval($this->accountRepos->getMetaValue($account, 'currency_id'));
$currency = $this->currencyRepos->findNull($currencyId);
if (0 === $currencyId) {
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
}
@@ -220,71 +228,103 @@ class ReconcileController extends Controller
}
/**
* @param JournalRepositoryInterface $repository
* @param TransactionJournal $journal
* @param TransactionJournal $journal
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*/
public function show(JournalRepositoryInterface $repository, TransactionJournal $journal)
public function show(TransactionJournal $journal)
{
if (TransactionType::RECONCILIATION !== $journal->transactionType->type) {
return redirect(route('transactions.show', [$journal->id]));
}
$subTitle = trans('firefly.reconciliation') . ' "' . $journal->description . '"';
// get main transaction:
$transaction = $repository->getAssetTransaction($journal);
$transaction = $this->repository->getAssetTransaction($journal);
$account = $transaction->account;
return view('accounts.reconcile.show', compact('journal', 'subTitle', 'transaction', 'account'));
}
/**
* @param Request $request
* @param Account $account
* @param Carbon $start
* @param Carbon $end
* @param ReconciliationStoreRequest $request
* @param JournalRepositoryInterface $repository
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function submit(Request $request, Account $account, Carbon $start, Carbon $end)
public function submit(ReconciliationStoreRequest $request, JournalRepositoryInterface $repository, Account $account, Carbon $start, Carbon $end)
{
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$transactions = $repository->getTransactionsById($request->get('transactions') ?? []);
Log::debug('In ReconcileController::submit()');
$data = $request->getAll();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$repository->reconcile($transaction); // mark as reconciled.
foreach ($data['transactions'] as $transactionId) {
$repository->reconcileById(intval($transactionId));
}
Log::debug('Reconciled all transactions.');
// create reconciliation transaction (if necessary):
if ('create' === $request->get('reconcile')) {
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
$reconciliation = $accountRepos->getReconciliation($account);
$difference = $request->get('difference');
if ('create' === $data['reconcile']) {
// get "opposing" account.
$reconciliation = $this->accountRepos->getReconciliation($account);
// store journal between these two.
$data = [
'what' => 'Reconciliation',
'source' => $account,
'destination' => $reconciliation,
'category' => '',
'budget_id' => 0,
'amount' => $difference,
'currency_id' => $account->getMeta('currency_id'),
'description' => trans(
'firefly.reconcilliation_transaction_title',
['from' => $start->formatLocalized($this->monthAndDayFormat), 'to' => $end->formatLocalized($this->monthAndDayFormat)]
),
'date' => $request->get('end'),
'notes' => join(',', $transactions->pluck('id')->toArray()),
$difference = $data['difference'];
$source = $reconciliation;
$destination = $account;
if (bccomp($difference, '0') === 1) {
// amount is positive. Add it to reconciliation?
$source = $account;
$destination = $reconciliation;
}
// data for journal
$description = trans(
'firefly.reconcilliation_transaction_title',
['from' => $start->formatLocalized($this->monthAndDayFormat), 'to' => $end->formatLocalized($this->monthAndDayFormat)]
);
$journalData = [
'type' => 'Reconciliation',
'description' => $description,
'user' => auth()->user()->id,
'date' => $data['end'],
'bill_id' => null,
'bill_name' => null,
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'tags' => null,
'interest_date' => null,
'transactions' => [[
'currency_id' => intval($this->accountRepos->getMetaValue($account, 'currency_id')),
'currency_code' => null,
'description' => null,
'amount' => app('steam')->positive($difference),
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,
'reconciled' => true,
'identifier' => 0,
'foreign_currency_id' => null,
'foreign_currency_code' => null,
'foreign_amount' => null,
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
'category_name' => null,
],
],
'notes' => implode(', ', $data['transactions']),
];
$journal = $repository->store($data);
// reconcile this transaction too:
$transaction = $journal->transactions()->first();
$repository->reconcile($transaction);
$journal = $repository->store($journalData);
}
Log::debug('End of routine.');
Session::flash('success', trans('firefly.reconciliation_stored'));
@@ -310,10 +350,8 @@ class ReconcileController extends Controller
$startDate = clone $start;
$startDate->subDays(1);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencyId = intval($account->getMeta('currency_id'));
$currency = $currencyRepos->find($currencyId);
$currencyId = intval($this->accountRepos->getMetaValue($account, 'currency_id'));
$currency = $this->currencyRepos->findNull($currencyId);
if (0 === $currencyId) {
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
}
@@ -335,17 +373,16 @@ class ReconcileController extends Controller
$transactions = $collector->getJournals();
$html = view('accounts.reconcile.transactions', compact('account', 'transactions', 'start', 'end', 'selectionStart', 'selectionEnd'))->render();
return Response::json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]);
return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]);
}
/**
* @param ReconciliationFormRequest $request
* @param AccountRepositoryInterface $repository
* @param TransactionJournal $journal
* @param ReconciliationUpdateRequest $request
* @param TransactionJournal $journal
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(ReconciliationFormRequest $request, AccountRepositoryInterface $repository, TransactionJournal $journal)
public function update(ReconciliationUpdateRequest $request, TransactionJournal $journal)
{
if (TransactionType::RECONCILIATION !== $journal->transactionType->type) {
return redirect(route('transactions.show', [$journal->id]));
@@ -356,8 +393,53 @@ class ReconcileController extends Controller
return redirect(route('accounts.reconcile.edit', [$journal->id]))->withInput();
}
// update journal using account repository. Keep it consistent.
$data = $request->getJournalData();
$repository->updateReconciliation($journal, $data);
$submitted = $request->getJournalData();
// amount pos neg influences the accounts:
$source = $this->repository->getJournalSourceAccounts($journal)->first();
$destination = $this->repository->getJournalDestinationAccounts($journal)->first();
if (bccomp($submitted['amount'], '0') === 1) {
// amount is positive, switch accounts:
list($source, $destination) = [$destination, $source];
}
// expand data with journal data:
$data = [
'type' => $journal->transactionType->type,
'description' => $journal->description,
'user' => $journal->user_id,
'date' => $journal->date,
'bill_id' => null,
'bill_name' => null,
'piggy_bank_id' => null,
'piggy_bank_name' => null,
'tags' => $submitted['tags'],
'interest_date' => null,
'book_date' => null,
'transactions' => [[
'currency_id' => intval($journal->transaction_currency_id),
'currency_code' => null,
'description' => null,
'amount' => app('steam')->positive($submitted['amount']),
'source_id' => $source->id,
'source_name' => null,
'destination_id' => $destination->id,
'destination_name' => null,
'reconciled' => true,
'identifier' => 0,
'foreign_currency_id' => null,
'foreign_currency_code' => null,
'foreign_amount' => null,
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
'category_name' => $submitted['category'],
],
],
'notes' => $this->repository->getNoteText($journal),
];
$this->repository->update($journal, $data);
// @codeCoverageIgnoreStart
if (1 === intval($request->get('return_to_edit'))) {

View File

@@ -84,6 +84,7 @@ class AccountController extends Controller
* @param string $what
*
* @return View
* @throws \RuntimeException
*/
public function create(Request $request, string $what = 'asset')
{
@@ -94,7 +95,7 @@ class AccountController extends Controller
$subTitle = trans('firefly.make_new_' . $what . '_account');
$roles = [];
foreach (config('firefly.accountRoles') as $role) {
$roles[$role] = strval(trans('firefly.account_role_' . $role));
$roles[$role] = (string)trans('firefly.account_role_' . $role);
}
// pre fill some data
@@ -128,18 +129,18 @@ class AccountController extends Controller
}
/**
* @param Request $request
* @param AccountRepositoryInterface $repository
* @param Account $account
* @param Request $request
* @param Account $account
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function destroy(Request $request, Account $account)
{
$type = $account->accountType->type;
$typeName = config('firefly.shortNamesByFullName.' . $type);
$name = $account->name;
$moveTo = $this->repository->find(intval($request->get('move_account_before_delete')));
$moveTo = $this->repository->findNull(intval($request->get('move_account_before_delete')));
$this->repository->destroy($account, $moveTo);
@@ -152,17 +153,19 @@ class AccountController extends Controller
/**
* Edit an account.
*
* @param Request $request
* @param Account $account
* @param Request $request
* @param Account $account
*
* @param AccountRepositoryInterface $repository
*
* @return View
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // long and complex but not that excessively so.
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @return View
*
* @throws FireflyException
* @throws \RuntimeException
*/
public function edit(Request $request, Account $account)
public function edit(Request $request, Account $account, AccountRepositoryInterface $repository)
{
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
@@ -183,23 +186,26 @@ class AccountController extends Controller
// pre fill some useful values.
// the opening balance is tricky:
$openingBalanceAmount = $account->getOpeningBalanceAmount();
$openingBalanceAmount = '0' === $account->getOpeningBalanceAmount() ? '' : $openingBalanceAmount;
$openingBalanceDate = $account->getOpeningBalanceDate();
$openingBalanceDate = 1900 === $openingBalanceDate->year ? null : $openingBalanceDate->format('Y-m-d');
$currency = $this->currencyRepos->find(intval($account->getMeta('currency_id')));
$openingBalanceAmount = strval($repository->getOpeningBalanceAmount($account));
$openingBalanceDate = $repository->getOpeningBalanceDate($account);
$default = app('amount')->getDefaultCurrency();
$currency = $this->currencyRepos->findNull(intval($repository->getMetaValue($account, 'currency_id')));
if (is_null($currency)) {
$currency = $default;
}
$preFilled = [
'accountNumber' => $account->getMeta('accountNumber'),
'accountRole' => $account->getMeta('accountRole'),
'ccType' => $account->getMeta('ccType'),
'ccMonthlyPaymentDate' => $account->getMeta('ccMonthlyPaymentDate'),
'BIC' => $account->getMeta('BIC'),
'accountNumber' => $repository->getMetaValue($account, 'accountNumber'),
'accountRole' => $repository->getMetaValue($account, 'accountRole'),
'ccType' => $repository->getMetaValue($account, 'ccType'),
'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'),
'BIC' => $repository->getMetaValue($account, 'BIC'),
'openingBalanceDate' => $openingBalanceDate,
'openingBalance' => $openingBalanceAmount,
'virtualBalance' => $account->virtual_balance,
'currency_id' => $currency->id,
'notes' => '',
'active' => $account->active,
];
/** @var Note $note */
$note = $this->repository->getNote($account);
@@ -274,79 +280,97 @@ class AccountController extends Controller
/**
* Show an account.
*
* @param Request $request
* @param Account $account
* @param string $moment
* @param Request $request
* @param Account $account
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // long and complex but not that excessively so.
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @throws FireflyException
*
*/
public function show(Request $request, Account $account, string $moment = '')
public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
{
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
return $this->redirectToOriginalAccount($account);
}
$range = Preferences::get('viewRange', '1M')->data;
if (null === $start) {
$start = session('start');
}
if (null === $end) {
$end = session('end');
}
if ($end < $start) {
throw new FireflyException('End is after start!'); // @codeCoverageIgnore
}
$today = new Carbon;
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$page = intval($request->get('page'));
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
$chartUri = route('chart.account.single', [$account->id]);
$start = null;
$end = null;
$periods = new Collection;
$currencyId = intval($account->getMeta('currency_id'));
$currency = $this->currencyRepos->find($currencyId);
$page = (int)$request->get('page');
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
$currencyId = (int)$this->repository->getMetaValue($account, 'currency_id');
$currency = $this->currencyRepos->findNull($currencyId);
if (0 === $currencyId) {
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
}
// prep for "all" view.
if ('all' === $moment) {
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
$chartUri = route('chart.account.all', [$account->id]);
$first = $this->journalRepos->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
}
// prep for "specific date" view.
if (strlen($moment) > 0 && 'all' !== $moment) {
$start = new Carbon($moment);
$start = app('navigation')->startOfPeriod($start, $range);
$end = app('navigation')->endOfPeriod($start, $range);
$fStart = $start->formatLocalized($this->monthAndDayFormat);
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
$subTitle = trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d')]);
$periods = $this->getPeriodOverview($account, $start);
}
// prep for current period view
if (0 === strlen($moment)) {
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
$fStart = $start->formatLocalized($this->monthAndDayFormat);
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
$subTitle = trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
$periods = $this->getPeriodOverview($account, null);
}
// grab journals:
$fStart = $start->formatLocalized($this->monthAndDayFormat);
$fEnd = $end->formatLocalized($this->monthAndDayFormat);
$subTitle = trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$periods = $this->getPeriodOverview($account, $end);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
if (null !== $start) {
$collector->setRange($start, $end);
}
$collector->setRange($start, $end);
$transactions = $collector->getPaginatedJournals();
$transactions->setPath(route('accounts.show', [$account->id, $moment]));
$transactions->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
$showAll = false;
return view(
'accounts.show',
compact('account', 'currency', 'moment', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
compact('account', 'showAll', 'currency', 'today', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
);
}
/**
* Show an account.
*
* @param Request $request
* @param Account $account
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*
* @throws FireflyException
*
*/
public function showAll(Request $request, Account $account)
{
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
return $this->redirectToOriginalAccount($account);
}
$end = new Carbon;
$today = new Carbon;
$start = $this->repository->oldestJournalDate($account);
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$page = (int)$request->get('page');
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
$currencyId = (int)$this->repository->getMetaValue($account, 'currency_id');
$currency = $this->currencyRepos->findNull($currencyId);
if (0 === $currencyId) {
$currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore
}
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
$periods = new Collection;
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
$transactions = $collector->getPaginatedJournals();
$transactions->setPath(route('accounts.show.all', [$account->id]));
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$showAll = true;
return view(
'accounts.show',
compact('account', 'showAll', 'currency', 'today', 'chartUri', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end')
);
}
@@ -354,12 +378,13 @@ class AccountController extends Controller
* @param AccountFormRequest $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function store(AccountFormRequest $request)
{
$data = $request->getAccountData();
$account = $this->repository->store($data);
$request->session()->flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
$request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
Preferences::mark();
// update preferences if necessary:
@@ -383,11 +408,11 @@ class AccountController extends Controller
}
/**
* @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository
* @param Account $account
* @param AccountFormRequest $request
* @param Account $account
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function update(AccountFormRequest $request, Account $account)
{
@@ -428,7 +453,9 @@ class AccountController extends Controller
* and for each period, the amount of money spent and earned. This is a complex operation which is cached for
* performance reasons.
*
* @param Account $account the account involved
* @param Account $account the account involved
*
* @param Carbon|null $date
*
* @return Collection
*
@@ -439,6 +466,9 @@ class AccountController extends Controller
$range = Preferences::get('viewRange', '1M')->data;
$start = $this->repository->oldestJournalDate($account);
$end = $date ?? new Carbon;
if ($end < $start) {
list($start, $end) = [$end, $start]; // @codeCoverageIgnore
}
// properties for cache
$cache = new CacheProperties;
@@ -449,37 +479,35 @@ class AccountController extends Controller
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
/** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = new Collection;
// loop dates
foreach ($dates as $date) {
foreach ($dates as $currentDate) {
// try a collector for income:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($date['start'], $date['end'])->setTypes([TransactionType::DEPOSIT])
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::DEPOSIT])
->withOpposingAccount();
$earned = strval($collector->getJournals()->sum('transaction_amount'));
$earned = (string)$collector->getJournals()->sum('transaction_amount');
// try a collector for expenses:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($date['start'], $date['end'])->setTypes([TransactionType::WITHDRAWAL])
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::WITHDRAWAL])
->withOpposingAccount();
$spent = strval($collector->getJournals()->sum('transaction_amount'));
$spent = (string)$collector->getJournals()->sum('transaction_amount');
$dateStr = $date['end']->format('Y-m-d');
$dateName = app('navigation')->periodShow($date['start'], $date['period']);
$dateName = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
$entries->push(
[
'string' => $dateStr,
'name' => $dateName,
'spent' => $spent,
'earned' => $earned,
'date' => clone $date['end'],]
'start' => $currentDate['start']->format('Y-m-d'),
'end' => $currentDate['end']->format('Y-m-d'),
]
);
}

View File

@@ -76,6 +76,7 @@ class LinkController extends Controller
* @param LinkType $linkType
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
* @throws \RuntimeException
*/
public function delete(Request $request, LinkTypeRepositoryInterface $repository, LinkType $linkType)
{
@@ -108,6 +109,7 @@ class LinkController extends Controller
* @param LinkType $linkType
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function destroy(Request $request, LinkTypeRepositoryInterface $repository, LinkType $linkType)
{
@@ -126,6 +128,7 @@ class LinkController extends Controller
* @param LinkType $linkType
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
* @throws \RuntimeException
*/
public function edit(Request $request, LinkType $linkType)
{
@@ -184,6 +187,7 @@ class LinkController extends Controller
* @param LinkTypeRepositoryInterface $repository
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function store(LinkTypeFormRequest $request, LinkTypeRepositoryInterface $repository)
{
@@ -212,6 +216,7 @@ class LinkController extends Controller
* @param LinkType $linkType
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function update(LinkTypeFormRequest $request, LinkTypeRepositoryInterface $repository, LinkType $linkType)
{

View File

@@ -22,6 +22,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Admin;
use Carbon\Carbon;
use FireflyConfig;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
@@ -31,7 +32,6 @@ use FireflyIII\Services\Github\Object\Release;
use FireflyIII\Services\Github\Request\UpdateRequest;
use Illuminate\Http\Request;
use Log;
use Response;
use Session;
/**
@@ -61,6 +61,8 @@ class UpdateController extends Controller
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Illuminate\Container\EntryNotFoundException
*/
public function index()
@@ -121,12 +123,20 @@ class UpdateController extends Controller
if ($check === -1) {
// there is a new FF version!
$string = strval(
trans(
'firefly.update_new_version_alert',
['your_version' => $current, 'new_version' => $first->getTitle(), 'date' => $first->getUpdated()->formatLocalized($this->monthAndDayFormat)]
)
);
// has it been released for more than three days?
$today = new Carbon;
if ($today->diffInDays($first->getUpdated(), true) > 3) {
$string = strval(
trans(
'firefly.update_new_version_alert',
[
'your_version' => $current,
'new_version' => $first->getTitle(),
'date' => $first->getUpdated()->formatLocalized($this->monthAndDayFormat),
]
)
);
}
}
if ($check === 0) {
// you are running the current version!
@@ -137,6 +147,6 @@ class UpdateController extends Controller
$string = strval(trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $first->getTitle()]));
}
return Response::json(['result' => $string]);
return response()->json(['result' => $string]);
}
}

View File

@@ -29,7 +29,6 @@ use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Http\Response as LaravelResponse;
use Preferences;
use Response;
use View;
/**
@@ -81,6 +80,7 @@ class AttachmentController extends Controller
* @param Attachment $attachment
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \RuntimeException
*/
public function destroy(Request $request, Attachment $attachment)
{
@@ -130,6 +130,7 @@ class AttachmentController extends Controller
* @param Attachment $attachment
*
* @return View
* @throws \RuntimeException
*/
public function edit(Request $request, Attachment $attachment)
{
@@ -142,6 +143,9 @@ class AttachmentController extends Controller
}
$request->session()->forget('attachments.edit.fromUpdate');
$preFilled['notes'] = $this->repository->getNoteText($attachment);
$request->session()->flash('preFilled', $preFilled);
return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle'));
}
@@ -150,6 +154,7 @@ class AttachmentController extends Controller
* @param Attachment $attachment
*
* @return \Illuminate\Http\RedirectResponse
* @throws \RuntimeException
*/
public function update(AttachmentFormRequest $request, Attachment $attachment)
{
@@ -182,7 +187,7 @@ class AttachmentController extends Controller
if ($this->repository->exists($attachment)) {
$content = $this->repository->getContent($attachment);
return Response::make(
return response()->make(
$content, 200, [
'Content-Type' => $attachment->mime,
'Content-Disposition' => 'inline; filename="' . $attachment->filename . '"',

View File

@@ -22,14 +22,13 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Auth;
use DB;
use FireflyConfig;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\User;
use Illuminate\Cookie\CookieJar;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Schema;
/**
* @codeCoverageIgnore
@@ -66,6 +65,7 @@ class LoginController extends Controller
*
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
*
* @throws \RuntimeException
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
@@ -103,6 +103,7 @@ class LoginController extends Controller
* @param CookieJar $cookieJar
*
* @return $this|\Illuminate\Http\RedirectResponse
* @throws \RuntimeException
*/
public function logout(Request $request, CookieJar $cookieJar)
{
@@ -120,26 +121,13 @@ class LoginController extends Controller
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \RuntimeException
*/
public function showLoginForm(Request $request)
{
// check for presence of tables:
$hasTable = Schema::hasTable('users');
if (!$hasTable) {
$message
= 'Firefly III could not find the "users" table. This is a strong indication your database credentials are wrong or the database has not been initialized. Did you follow the installation instructions correctly?';
return view('error', compact('message'));
}
// check for presence of currency:
$currency = TransactionCurrency::where('code', 'EUR')->first();
if (null === $currency) {
$message
= 'Firefly III could not find the EURO currency. This is a strong indication the database has not been initialized correctly. Did you follow the installation instructions?';
return view('error', compact('message'));
$count = DB::table('users')->count();
if ($count === 0) {
return redirect(route('register')); // @codeCoverageIgnore
}
// forget 2fa session thing.

View File

@@ -75,6 +75,7 @@ class ResetPasswordController extends Controller
if (true === $singleUserMode && $userCount > 0) {
$allowRegistration = false;
}
return view('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email, 'allowRegistration' => $allowRegistration]
);

View File

@@ -40,6 +40,7 @@ class TwoFactorController extends Controller
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*
* @throws \RuntimeException
* @throws FireflyException
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
@@ -91,6 +92,7 @@ class TwoFactorController extends Controller
*
* @return mixed
* @SuppressWarnings(PHPMD.UnusedFormalParameter) // it's unused but the class does some validation.
* @throws \RuntimeException
*/
public function postIndex(TokenFormRequest $request, CookieJar $cookieJar)
{

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