Compare commits

...

442 Commits

Author SHA1 Message Date
James Cole
53c71bb7a2 Merge branch 'release/4.7.11' 2019-02-10 14:53:57 +01:00
James Cole
3c036ae021 Fix issue with time stamps. 2019-02-10 14:53:24 +01:00
James Cole
bf89d9956d Update language strings. 2019-02-10 14:33:15 +01:00
James Cole
71104f375c Fix tests 2019-02-10 14:33:03 +01:00
James Cole
4c94820cf4 Update meta files. 2019-02-10 14:32:34 +01:00
James Cole
8998c9a672 Extra code for #1975 2019-02-10 10:54:30 +01:00
James Cole
ccf60f4cdc Back to classic build. 2019-02-10 08:07:25 +01:00
James Cole
c5af1d363c Add audit trail messages to several controllers. 2019-02-10 08:03:09 +01:00
James Cole
c6e3b54705 Make update code slightly more robust. 2019-02-10 07:59:11 +01:00
James Cole
4f274a290e Generic debug info. 2019-02-09 20:44:31 +01:00
James Cole
1774bcbabe Add copyright statements and newlines. 2019-02-09 10:36:59 +01:00
James Cole
492c11784b Update with manifest commands. 2019-02-09 06:40:55 +01:00
James Cole
21ddbd220a Include lib for arm 2019-02-08 17:40:29 +01:00
James Cole
e4a95e55ed Remove copy argument. 2019-02-08 17:34:46 +01:00
James Cole
3a0eb5a428 Do actual build 2019-02-08 17:31:32 +01:00
James Cole
e55fd968cf Rename file 2019-02-08 17:31:25 +01:00
James Cole
d41be08b48 Rename file 2019-02-08 17:30:42 +01:00
James Cole
a18272513d Fix YML 2019-02-08 17:28:04 +01:00
James Cole
e88061199c Trigger a new build. 2019-02-08 17:17:19 +01:00
James Cole
d0d7c437f2 Different build flow. 2019-02-08 17:15:54 +01:00
James Cole
a1ac1a4a29 Remove empty header from changelog [skip ci] 2019-02-08 17:01:49 +01:00
James Cole
41d22876c4 Update changelog and version. 2019-02-08 17:00:46 +01:00
James Cole
e1bb0298cb Fix category use date. 2019-02-08 16:56:07 +01:00
James Cole
1ec2772255 Fix #2052 2019-02-08 16:51:29 +01:00
James Cole
40d77d82cd Bunq import can now handle timestamps. 2019-02-08 16:45:42 +01:00
James Cole
311d51464d Add support for #2006 2019-02-08 07:14:45 +01:00
James Cole
d63c9c9aea Add audit logging. 2019-02-08 07:13:59 +01:00
James Cole
f1e83f240e Build with a new distribution. 2019-02-08 03:21:34 +01:00
James Cole
b0f847959f Merge pull request #2058 from skuzzle/develop
Remove console.log statement
2019-02-05 15:22:12 +01:00
Simon Taddiken
d3d4439b03 Remove console.log statement 2019-02-05 15:02:36 +01:00
James Cole
0e1da3f797 Fix webbased upgrade routine. 2019-02-04 20:35:46 +01:00
James Cole
def95df49e Fix link in changelog [skip ci] 2019-02-03 20:20:24 +01:00
James Cole
73c8c6de37 Disable manifest push [skip ci] 2019-02-03 20:19:59 +01:00
James Cole
25b2b43a38 Fix for #2049 2019-02-03 18:25:58 +01:00
James Cole
1fc2c998de Merge pull request #2048 from nescafe2002/patch-1
Fix delete-account confirmation
2019-02-03 14:52:40 +01:00
Joris
b7a577cc4c Fix delete-account confirmation 2019-02-03 14:44:32 +01:00
James Cole
2cdedd9c29 Merge tag '4.7.10' into develop
4.7.10
2019-02-03 10:10:41 +01:00
James Cole
cf47daa2a0 Merge branch 'release/4.7.10' 2019-02-03 10:10:39 +01:00
James Cole
926e2db1d6 Update meta files for new release. 2019-02-03 10:09:04 +01:00
James Cole
d092034ec5 Updated translations [skip ci] 2019-02-03 09:21:37 +01:00
James Cole
d13b9a0cc3 Mention amd specifically. 2019-02-03 09:05:40 +01:00
James Cole
bbbaf6c868 Small textual changes [skip ci] 2019-02-03 07:51:34 +01:00
James Cole
833add99a0 Reverse build order, add manifest creation. 2019-02-03 07:00:50 +01:00
James Cole
b54e7f0d46 Remove platform argument. 2019-02-03 06:33:18 +01:00
James Cole
a90981481f Edit in build command. 2019-02-02 19:26:02 +01:00
James Cole
edff3d7fb0 Remove target platform reference 2019-02-02 19:24:53 +01:00
James Cole
88d65b4784 Switch args around. 2019-02-02 19:22:03 +01:00
James Cole
6db869de23 Get docker version 2019-02-02 19:16:19 +01:00
James Cole
c645cb18e5 Check experimental flag. 2019-02-02 19:13:10 +01:00
James Cole
298132298b Enable experimental things. 2019-02-02 19:10:46 +01:00
James Cole
400b50a1f0 Enable experimental features. 2019-02-02 19:05:11 +01:00
James Cole
5b597e9b1f Set the platform to ARM. 2019-02-02 18:58:49 +01:00
James Cole
e55de9c1d5 No manifest commands. 2019-02-02 18:07:03 +01:00
James Cole
33ccf7c707 Improve build scripts. 2019-02-02 17:59:18 +01:00
James Cole
6b94210de5 Include adm64 build and manifest stuff. 2019-02-02 17:20:15 +01:00
James Cole
745624f044 Make script executable. 2019-02-02 17:10:47 +01:00
James Cole
68956eabf2 Refer to ARM script. 2019-02-02 17:08:46 +01:00
James Cole
87591f6868 Also expand dockerfile. 2019-02-02 16:10:55 +01:00
James Cole
cc238a639e Expand some commands. 2019-02-02 16:08:15 +01:00
James Cole
de6758a972 Update docker file and entrypoint. 2019-02-02 15:56:36 +01:00
James Cole
49647eedae Fix command again. 2019-02-02 15:49:06 +01:00
James Cole
f24e35236f Fix command. 2019-02-02 15:46:37 +01:00
James Cole
6f200a423e Correct command. 2019-02-02 15:33:33 +01:00
James Cole
ef57c0601a Let's see what happens when we build using another base. 2019-02-02 15:30:23 +01:00
James Cole
9632e99bd3 Fix #2043 2019-02-02 14:33:24 +01:00
James Cole
93e18ea195 Remove unused values from charts. 2019-02-02 12:34:58 +01:00
James Cole
f39676eedd Fix for #2041 2019-02-02 12:28:37 +01:00
James Cole
1d73ff7c13 Fix test coverage. [skip ci] 2019-02-02 09:53:19 +01:00
James Cole
384e64d94d Update docs [skip ci] 2019-02-02 07:04:08 +01:00
James Cole
96bb880d1b #2034 2019-02-02 07:00:09 +01:00
James Cole
cf307a00e1 Code for #2037 2019-02-02 06:10:52 +01:00
James Cole
5a97bcb123 Update docker decrypt location. 2019-01-31 21:00:41 +01:00
James Cole
50f7620d7a See what happens when we try ARM. 2019-01-31 20:40:03 +01:00
James Cole
78ec3ebe59 Remove test routine, push image to test repository. 2019-01-31 20:23:09 +01:00
James Cole
96f0faa546 Change Travis build. 2019-01-31 20:09:30 +01:00
James Cole
4307bf3b83 Remove Firefly III's ability to encrypt data in the database. 2019-01-31 19:56:09 +01:00
James Cole
d56bd85328 New changelog. [skip ci] 2019-01-28 20:26:37 +01:00
James Cole
9f2f258ad9 Added new language, Chinese Traditional. 2019-01-28 20:10:52 +01:00
James Cole
894b48df8e Introduce new model for future remodeling of split transactions. 2019-01-28 20:00:40 +01:00
James Cole
195fba5931 New translations. 2019-01-28 19:37:15 +01:00
James Cole
0556516524 Summarise import options. 2019-01-28 19:36:30 +01:00
James Cole
5cad4e9d82 Fix #1989 2019-01-28 19:36:17 +01:00
James Cole
8607fd4997 Fix #2033 2019-01-28 18:21:22 +01:00
James Cole
d905849b71 Experimental fix for #2031 2019-01-27 21:23:18 +01:00
James Cole
968505ac0e Route can be null. 2019-01-27 18:24:11 +01:00
James Cole
e482b079df Cleanup help file. 2019-01-27 18:23:47 +01:00
James Cole
13cddd8f12 Fix bill test 2019-01-27 18:11:10 +01:00
James Cole
20b458f35d Ignore form action when doing oAuth2. 2019-01-27 17:15:40 +01:00
James Cole
cec8210d8b Fix #2009 2019-01-27 17:09:39 +01:00
James Cole
e6ff895eff Fix #2001 2019-01-27 17:02:45 +01:00
James Cole
74ff17da7e Fix #1990 2019-01-27 16:43:43 +01:00
James Cole
7e1d430003 Fix #1967 2019-01-27 16:42:28 +01:00
James Cole
eeff2895aa Fix #1923 2019-01-27 16:36:08 +01:00
James Cole
f6d88521dd Fix test coverage. 2019-01-27 12:30:52 +01:00
James Cole
c3e6e4f034 Simplify budget repository 2019-01-27 11:05:22 +01:00
James Cole
6c09330e74 Simplify recurring repository. 2019-01-27 11:00:28 +01:00
James Cole
b100c02779 Expand income and expense info without a category. 2019-01-27 10:51:34 +01:00
James Cole
ef6f00fcf5 Make sure "no category" is added to API as well. 2019-01-27 10:51:14 +01:00
James Cole
ad9405887a Remove cash again. 2019-01-27 10:51:00 +01:00
James Cole
01e45de605 Include cash accounts in income and expense charts. 2019-01-27 07:57:10 +01:00
James Cole
aebefe8bcf Fix currency mapper test 2019-01-27 07:48:57 +01:00
James Cole
5e41641d7c Simplify account transformer 2019-01-27 07:48:49 +01:00
James Cole
0f3b3a07d1 Remove debug code. 2019-01-27 07:48:37 +01:00
James Cole
156d2fbaa4 Simplify autocomplete controller 2019-01-27 07:48:29 +01:00
James Cole
4866b9dabb Fix old category chart 2019-01-27 07:48:17 +01:00
James Cole
62ce9660b4 Simplify rule group controller 2019-01-27 07:47:37 +01:00
James Cole
873c2ce10d New routes for new API endpoints. 2019-01-26 20:19:06 +01:00
James Cole
2c2410e710 Category overview chart in API and support methods. 2019-01-26 20:18:42 +01:00
James Cole
624eb0f958 Add new revenue and expense overview chart endpoint to API 2019-01-26 20:10:48 +01:00
James Cole
770e44d1bd Add new tag-cloud API endpoint. 2019-01-26 20:10:35 +01:00
James Cole
7144798377 Add new chart API endpoints. 2019-01-26 12:11:45 +01:00
James Cole
606ff3ed00 Fix problem with rule trigger tester. 2019-01-26 12:11:37 +01:00
James Cole
ca731adce7 Add account name to piggy bank transformer API. 2019-01-26 12:11:23 +01:00
James Cole
ca71f3008c Fix a bug where the importer was unable to create new currencies. 2019-01-26 12:11:10 +01:00
James Cole
7c56c14fa0 Add fallback for empty front page account preferences thing. 2019-01-26 12:10:53 +01:00
James Cole
e3433aa95b Add pie chart for available budget API 2019-01-26 12:10:35 +01:00
James Cole
0df00556db Make sure chart end point returns machine readable dates. 2019-01-26 12:10:21 +01:00
James Cole
a55dd97d51 Add ability to return single preference to the API 2019-01-26 12:10:02 +01:00
James Cole
b52959d41a Add limit parameter to capabilities of API 2019-01-26 12:09:46 +01:00
James Cole
163b0a2105 Add limit parameter to /budgets/x/transactions API endpoint. 2019-01-26 12:09:32 +01:00
James Cole
d33c89a8ee Add start and end data to the available_budget list endpoint API 2019-01-26 12:09:16 +01:00
James Cole
d0d73c5e3e Add limit parameter to account/x/transactions API end point. 2019-01-26 12:08:41 +01:00
James Cole
799331b945 New API endpoints. 2019-01-18 05:38:23 +01:00
James Cole
43073fa1fc Translation updates. 2019-01-12 10:32:59 +01:00
James Cole
7f91ff4b0c Fix #1996 2019-01-11 16:57:40 +01:00
James Cole
ba778d4c60 Update some issue templates. 2019-01-08 17:05:42 +01:00
James Cole
cddb3d82dd Expand changelog. 2019-01-07 18:23:04 +01:00
James Cole
a221f02393 Fix #1983 2019-01-07 18:19:48 +01:00
James Cole
fa4959fc6a Fix #1979 2019-01-07 18:07:59 +01:00
James Cole
bbd68e78c1 Fix #1975 2019-01-07 18:05:43 +01:00
James Cole
3c20938e0f Merge pull request #1977 from BastiaanN/docker-cache
Added memcached support and zend opcache
2019-01-07 15:35:28 +01:00
Bastiaan Nijkamp
94745cb3d5 Added memcached support and zend opcache 2019-01-07 12:14:10 +01:00
James Cole
602b328914 Add tokenizer to composer.lock [skip ci] 2019-01-06 16:55:06 +01:00
James Cole
27802c930f Remove trial code, restore repository. Should not have committed this. Oh well. Let's continue this in a branch like I'm supposed to. 2019-01-06 16:23:37 +01:00
James Cole
3b4622a9ac Add API config. 2019-01-06 16:01:01 +01:00
James Cole
18fb2e91b1 Remove not working command. 2019-01-06 16:00:36 +01:00
James Cole
214cd9c262 Require tokenizer. 2019-01-06 16:00:23 +01:00
James Cole
337c289a74 This combination of JS things works. 2019-01-06 13:37:25 +01:00
James Cole
0d560ec442 Fix for #1968 2019-01-04 17:10:16 +01:00
James Cole
a4d4bf3006 Remove not working parameters, add more debug 2019-01-04 17:03:34 +01:00
James Cole
40028c8be7 These are all the files from the Tabler react repos, made to work with laravel and webpack. 2019-01-04 17:03:16 +01:00
James Cole
961e7e92b3 Some new files for JS rendering of new layout. 2019-01-04 16:37:24 +01:00
James Cole
d3576c4151 Update composer file. 2019-01-04 16:15:13 +01:00
James Cole
1d51a0f396 Update some v2 views. 2019-01-03 19:02:47 +01:00
James Cole
f62b7e4ae9 Update test component. 2019-01-03 19:02:31 +01:00
James Cole
62135bc1cb Updated changelog. 2019-01-03 19:02:18 +01:00
James Cole
b245facdfe Small fixes. 2019-01-03 19:01:32 +01:00
James Cole
577f024310 Make code default for React things. 2019-01-03 19:01:15 +01:00
James Cole
1c2206cb9f Fix issue with recurring transactions and piggy banks. 2019-01-03 18:57:34 +01:00
James Cole
16ba65c424 Merge pull request #1963 from BoGnY/fix/csp-directive
Fixed missing CSP directive and value
2019-01-03 16:13:33 +01:00
Luca Bognolo
59cfaa20ab Fixed wrong CSP value
Signed-off-by: Luca Bognolo <git@bogny.eu>
2019-01-03 16:04:48 +01:00
Luca Bognolo
ab0471c78e Fixed missing CSP directive and value
Signed-off-by: Luca Bognolo <git@bogny.eu>
2019-01-03 00:21:21 +01:00
James Cole
464642250b Fix #1955. 2019-01-01 19:32:37 +01:00
James Cole
d7bf9e234c Fix test coverage. 2019-01-01 18:03:24 +01:00
James Cole
bf257574f9 Update PR template [skip ci] 2019-01-01 17:56:38 +01:00
James Cole
92e42199b5 Wrote the changelog so I don't have to do it later [skip ci] 2019-01-01 17:50:44 +01:00
James Cole
99b0b24a89 Enable currencies if not enabled yet. #1952 2019-01-01 17:17:38 +01:00
James Cole
d86383eba8 Set correct copyright notice @BoGnY #1947 2019-01-01 16:49:41 +01:00
James Cole
4fc12f232a Merge pull request #1951 from BoGnY/feature/cer-provider
Implemented multiple Currency Exchange Rates sites engine
2019-01-01 16:47:01 +01:00
Luca Bognolo
729483102e Implemented multiple Currency Exchange Rates sites engine
Signed-off-by: Luca Bognolo <git@bogny.eu>
2019-01-01 16:32:22 +01:00
James Cole
7ac00935d5 Update old assets. 2019-01-01 15:44:55 +01:00
James Cole
639be5b104 Add newlines to views. 2019-01-01 15:43:03 +01:00
James Cole
17359c5e42 Various experiments with JS and React and what-not. 2019-01-01 15:41:54 +01:00
James Cole
7aa5eee3aa Better fix for date. 2019-01-01 15:29:24 +01:00
James Cole
98d6a7f32e Update some meta files [skip ci] 2019-01-01 14:11:57 +01:00
James Cole
0475b68817 Merge pull request #1948 from BoGnY/feature/croatian-kuna
Add Croatian kuna to currency seeder
2019-01-01 13:15:01 +01:00
Luca Bognolo
2a89d49ba7 Add Croatian kuna to currency seeder
Signed-off-by: Luca Bognolo <git@bogny.eu>
2018-12-31 17:53:13 +01:00
James Cole
aeab5f0333 Fix to make sure that the index respects the fiscal year. 2018-12-31 13:44:24 +01:00
James Cole
f80de95bb0 Refactor code to traits. 2018-12-31 08:11:57 +01:00
James Cole
e7bcc01fe8 Refactor code to traits. 2018-12-31 07:58:13 +01:00
James Cole
9fcbce241e Will speed up Docker start. 2018-12-31 07:57:33 +01:00
James Cole
78a71fb7c6 Add copyright [skip ci] 2018-12-31 07:57:21 +01:00
James Cole
3e25d66902 Add newlines and copyright notices. 2018-12-31 07:48:23 +01:00
James Cole
005e4ba4d1 Improve entrypoint script so Docker will build better. 2018-12-30 15:46:09 +01:00
James Cole
0f83582fed Fix #1944 2018-12-30 15:44:33 +01:00
James Cole
d736ffec8e Fix #1945 2018-12-30 15:31:07 +01:00
James Cole
27d6091e45 Make sure favicon links are relative. #1942 2018-12-30 14:51:50 +01:00
James Cole
290405b987 Some meta improvements [skip ci] 2018-12-30 06:19:40 +01:00
James Cole
7fa2fed147 Fix for #1938 2018-12-30 06:19:16 +01:00
James Cole
fd233510ee Fix https://github.com/firefly-iii/firefly-iii/issues/1933 / https://github.com/Adldap2/Adldap2/issues/629 2018-12-30 06:10:46 +01:00
James Cole
354be8dc88 Fix for #1927 2018-12-29 21:57:24 +01:00
James Cole
9750bcba76 Another fix for https://github.com/firefly-iii/firefly-iii/issues/1939 2018-12-29 21:53:34 +01:00
James Cole
15d08ca17b Fix for https://github.com/firefly-iii/firefly-iii/issues/1939 2018-12-29 21:51:20 +01:00
James Cole
1bc72fa49f Flatten command, different entrypoint command. 2018-12-27 15:21:37 +01:00
James Cole
68061fd292 Rename some translations. 2018-12-27 06:05:01 +01:00
James Cole
2b77e9d96d Update Docker files. 2018-12-27 06:04:49 +01:00
James Cole
5c48d2d56a Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Fix fullcalendar.mi.js links
2018-12-27 05:24:38 +01:00
James Cole
11a0734009 Merge pull request #1929 from a1ex4/develop
Fix fullcalendar.min.js links
2018-12-27 05:05:16 +01:00
a1ex4
2ccbfe45f2 Fix fullcalendar.mi.js links 2018-12-26 18:43:50 +01:00
James Cole
3793b08d90 Build new packages for Sandstorm. 2018-12-23 19:21:54 +01:00
James Cole
06b63209b1 Show debug info in sandstorm. 2018-12-23 19:21:40 +01:00
James Cole
02e318b3e6 New file list. 2018-12-23 19:21:18 +01:00
James Cole
3b78b26039 Merge tag '4.7.9' into develop
4.7.9
2018-12-23 18:24:34 +01:00
James Cole
f57fc06347 Merge branch 'release/4.7.9' 2018-12-23 18:24:28 +01:00
James Cole
32a14ab8e0 Update composer file. 2018-12-23 18:19:30 +01:00
James Cole
5fafe6e4f4 Update changelog and version references. 2018-12-23 18:19:19 +01:00
James Cole
ee907aba34 New language strings 2018-12-23 18:18:53 +01:00
James Cole
2ae9a6f020 Remove curl build, since bunq seems to work fine without it.
Can I tag people in commit messages? @OGKevin
2018-12-23 10:57:46 +01:00
James Cole
479841a609 Updated favicons. [skip ci] 2018-12-23 07:50:55 +01:00
James Cole
10da45edce Add some JS and CSS resources. 2018-12-23 07:35:15 +01:00
James Cole
36c4a30fe3 Fix currency ID index error. 2018-12-23 07:34:51 +01:00
James Cole
d4542cc3fc Fix currency ID index error. 2018-12-23 07:34:23 +01:00
James Cole
dea02e374f Fix currency ID index error. 2018-12-23 07:34:00 +01:00
James Cole
91deac706c Some new code for the new layout. 2018-12-23 07:21:47 +01:00
James Cole
17e85ca2cf Update docker files. 2018-12-22 06:45:07 +01:00
James Cole
91593335ef Available budget end point also gives info on spent info #1884 2018-12-22 06:40:25 +01:00
James Cole
d27176c0b3 Fix #1828 2018-12-22 06:21:06 +01:00
James Cole
070e1e81ae Fix #1859 2018-12-22 06:07:57 +01:00
James Cole
2c7d94e5e9 Update tests and code. 2018-12-21 16:38:10 +01:00
James Cole
a5520d45e7 Store booleans correctly. 2018-12-21 15:42:57 +01:00
James Cole
922c8703f5 Fix for #1890 2018-12-21 15:42:40 +01:00
James Cole
75cc024e28 Expand account types to fix https://github.com/firefly-iii/api-docs-generator/issues/2 2018-12-21 15:26:48 +01:00
James Cole
75c6da7730 Fix #1909 2018-12-21 10:55:34 +01:00
James Cole
35c8b2fce8 Fix #1901 2018-12-21 10:17:38 +01:00
James Cole
4f5d8f830e Various fixes and checks. 2018-12-21 10:11:18 +01:00
James Cole
78cb6da21a Fix for #1898 2018-12-21 10:11:01 +01:00
James Cole
a7e1a51476 Make sure rules work. 2018-12-21 09:01:21 +01:00
James Cole
a8ff77addd Various improvements to Docker files. 2018-12-21 07:36:53 +01:00
James Cole
3c9c46d574 Expand tests 2018-12-21 07:36:40 +01:00
James Cole
8ede404b8a Refer to correct field name. 2018-12-21 06:51:21 +01:00
James Cole
a7585e3040 Fix for #1985 2018-12-21 06:51:00 +01:00
James Cole
cd47b45fce Add some debug info to bunq and update the composer file [skip ci] 2018-12-20 23:06:47 +01:00
James Cole
b6c23b8eb3 Fix #1893 2018-12-20 22:32:33 +01:00
James Cole
297e12f6e4 New language strings. 2018-12-20 22:23:22 +01:00
James Cole
29b02fcac2 Fix issue with spaces in tag report. 2018-12-20 22:19:07 +01:00
James Cole
0c2218762c Update entry point script. 2018-12-20 22:13:16 +01:00
James Cole
27bc03fc20 Cover all transformers. 2018-12-20 22:03:34 +01:00
James Cole
84b3195e9b Improve transformer coverage. 2018-12-20 20:50:05 +01:00
James Cole
6f54f41946 Add new tests for transformers. 2018-12-20 05:46:05 +01:00
James Cole
c1ae0ab57d Update some tests. 2018-12-19 19:23:52 +01:00
James Cole
446ff81335 Make sure transformers match API definition. 2018-12-19 19:02:16 +01:00
James Cole
03b4a50317 Improve transformers and tests 2018-12-19 06:06:01 +01:00
James Cole
06c3362332 New language strings. 2018-12-18 20:08:38 +01:00
James Cole
5f059d02ad Add a profile warning for access tokens [skip ci] 2018-12-18 20:00:04 +01:00
James Cole
3e71a103a2 Improve test coverage. 2018-12-18 19:57:23 +01:00
James Cole
e46561347d Some rule fixes. 2018-12-18 07:08:46 +01:00
James Cole
a3f33ae888 Go from get to post. 2018-12-18 07:08:35 +01:00
James Cole
f71359e73d Improve test coverage. 2018-12-18 07:08:23 +01:00
James Cole
a0b475d8ef Improve test coverage. 2018-12-18 07:07:51 +01:00
James Cole
f3a597cd12 Improve test coverage. 2018-12-18 06:57:42 +01:00
James Cole
29f2ee93d1 Improve test coverage. 2018-12-18 06:49:26 +01:00
James Cole
454b3ebd97 Improve tests. 2018-12-17 07:09:44 +01:00
James Cole
89942ee49c Improve test coverage for API. 2018-12-16 13:55:19 +01:00
James Cole
746bd2ce92 Do not email about OAuth exceptions. 2018-12-16 13:15:09 +01:00
James Cole
747602a9cb Make a new abstract class for transformers. 2018-12-15 22:03:42 +01:00
James Cole
8ce43a3fe1 Make sure transformers can be mocked. 2018-12-15 22:03:05 +01:00
James Cole
1284f9cecc Refactored API code surrounding accounts to make transformers mockable. 2018-12-15 07:59:49 +01:00
James Cole
c54541b839 Learned that I should not refer to env vars directly so I removed all references. 2018-12-15 07:59:02 +01:00
James Cole
4bd94e5450 Update request data to match API definition. 2018-12-14 18:33:07 +01:00
James Cole
2a30293905 Improve test coverage. 2018-12-12 20:30:25 +01:00
James Cole
159fffef2e Improve test coverage. 2018-12-10 21:45:44 +01:00
James Cole
5313652d7a New translations. 2018-12-09 20:56:04 +01:00
James Cole
ae4612f134 Fix test coverage. 2018-12-09 20:54:11 +01:00
James Cole
97f6e68164 Complete accounts and bills end point. 2018-12-09 13:09:43 +01:00
James Cole
108d43f967 Budgets and budget limits end point. 2018-12-09 08:45:53 +01:00
James Cole
b0e1c85c55 Expand API for categories. 2018-12-09 06:58:03 +01:00
James Cole
82e4055fa6 Expand currency endpoint. 2018-12-09 06:51:53 +01:00
James Cole
2a68ce6c90 Expand config API endpoint. 2018-12-09 06:39:56 +01:00
James Cole
05b0425929 Expand API and routes. 2018-12-08 21:26:20 +01:00
James Cole
3b15415a1b Build import job API endpoint. 2018-12-08 08:22:53 +01:00
James Cole
00fb809ab9 Remove include parameter. 2018-12-08 08:22:34 +01:00
James Cole
494aa15567 Refactored and extended link types. 2018-12-08 07:57:29 +01:00
James Cole
07450f9f23 Update preferences API. 2018-12-07 20:39:36 +01:00
James Cole
f0de469053 Expand API for recurring transactions. 2018-12-07 20:20:54 +01:00
James Cole
8e4092e7d7 Code and routes for rules. 2018-12-07 16:03:05 +01:00
James Cole
9a2e5c36a1 Finish up rule groups API 2018-12-07 15:36:04 +01:00
James Cole
b782316cc0 Update rule group API 2018-12-07 07:49:16 +01:00
James Cole
3e84f9664f Update API for tags. 2018-12-07 07:41:12 +01:00
James Cole
01e789f5ce New translations. 2018-12-05 19:24:42 +01:00
James Cole
b2381f4657 Add tag endpoint. 2018-12-05 19:12:38 +01:00
James Cole
64a3e46cbe New endpoints for transactions. 2018-12-04 19:36:54 +01:00
James Cole
c0d6d0e28e Update API to match new end points. 2018-12-03 15:57:15 +01:00
James Cole
c13d0da9fa Mark new version 2018-12-03 07:18:36 +01:00
James Cole
050334a648 Various API updates. 2018-12-03 07:18:05 +01:00
James Cole
0256337855 Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Fix typo
2018-12-03 07:17:19 +01:00
James Cole
bb073e4b6e Merge pull request #1891 from emansih/develop
Fix typo
2018-12-02 16:03:06 +01:00
Daniel Quah
40341ac14e Fix typo 2018-12-02 22:14:51 +08:00
James Cole
4420df6e5d New views for password reset, login and other user forms. 2018-11-25 11:31:02 +01:00
James Cole
99cc7a9a60 Upgrade datepicker. 2018-11-25 07:07:44 +01:00
James Cole
7ec1b985d0 Fix #1835 2018-11-25 07:04:35 +01:00
James Cole
9f19d26a23 Working test code. 2018-11-25 06:37:26 +01:00
James Cole
e766614630 Title for login page. 2018-11-25 06:37:14 +01:00
James Cole
ad49553b9c New favicons. 2018-11-25 06:37:03 +01:00
James Cole
1b3b39d2ea Add option to disable the X-Frame header 2018-11-24 07:24:32 +01:00
James Cole
cb68505204 Merge branch 'layout-v2' into develop
* layout-v2:
  First version of login page.
  Make FA and Google Font local
  Basic views.
  All assets for tabler layout.
2018-11-24 07:15:32 +01:00
James Cole
a574dca0cc Make sure pref is always filled in. 2018-11-23 10:39:33 +01:00
James Cole
c3fa1612d6 Fix for #1811 2018-11-23 08:40:08 +01:00
James Cole
7a8f6d8660 Update composer libs. 2018-11-23 08:32:23 +01:00
James Cole
9dda801fae Some new strings. 2018-11-23 08:32:11 +01:00
James Cole
344742c493 Improve bunq import for #1857 2018-11-23 08:31:58 +01:00
James Cole
886d05d436 Fix for #1622 and a special debug view. 2018-11-23 08:31:00 +01:00
James Cole
baac2ad921 Add Swedish to config file [skip ci] 2018-11-21 06:25:56 +01:00
James Cole
c3337c9bac Fix #1878 2018-11-21 06:21:57 +01:00
James Cole
6a6ca22bf0 Merge branch 'develop' into layout-v2
* develop:
  Fix date #1877
  Fix for #1877
  Auth routes now have names.
  First step towards a debug view for transactions.
  Username for FinTS import is not mandatory.
2018-11-21 06:20:23 +01:00
James Cole
f873f5488f Fix date #1877 2018-11-21 06:13:30 +01:00
James Cole
e18f843a57 Fix for #1877 2018-11-21 06:08:14 +01:00
James Cole
56a92505bd Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Username for FinTS import is not mandatory.
2018-11-21 05:55:37 +01:00
James Cole
a8bc7dd7c1 Auth routes now have names. 2018-11-21 05:55:11 +01:00
James Cole
94614550fc First step towards a debug view for transactions. 2018-11-21 05:54:57 +01:00
James Cole
b2052615e3 First version of login page. 2018-11-21 05:52:57 +01:00
James Cole
f51b9217f5 Make FA and Google Font local 2018-11-21 05:52:34 +01:00
James Cole
d892a87d1d Merge pull request #1876 from bnw/develop
Username for FinTS import is not mandatory.
2018-11-19 10:52:51 +01:00
Ben
b7182f9462 Username for FinTS import is not mandatory. 2018-11-18 22:36:05 +01:00
James Cole
79518753ad Basic views. 2018-11-17 08:30:11 +01:00
James Cole
01634ed5e9 All assets for tabler layout. 2018-11-17 08:29:52 +01:00
James Cole
f7abf8a02d Support multiple layouts. 2018-11-17 08:28:04 +01:00
James Cole
3f7f1a50e7 Fix #1864 2018-11-16 19:23:06 +01:00
James Cole
a5a770e750 Fix for #1766 2018-11-16 15:26:37 +01:00
James Cole
9cd10f58ed Expand API with fields: liability_type, liability_amount, liability_start_date, interest, interest_period. Improve IBAN field. #1866 2018-11-14 19:41:36 +01:00
James Cole
5011531066 Small chart improvements for #1865 2018-11-12 19:31:00 +01:00
James Cole
d1c7a9767a Remove reference to temp_amount 2018-11-12 19:17:17 +01:00
James Cole
d78e11170b Fix string. 2018-11-11 20:09:50 +01:00
James Cole
74f8dceb38 Fix #1865 2018-11-11 20:09:35 +01:00
James Cole
1fbf91c768 Fix tests and improve string. 2018-11-11 08:34:38 +01:00
James Cole
edf764aaf4 Will now warn about non-existent attachments. 2018-11-11 07:03:36 +01:00
James Cole
7380c5096e Fix test coverage. 2018-11-10 15:15:29 +01:00
James Cole
45699f13fc Update composer files. 2018-11-10 10:50:41 +01:00
James Cole
1fd8c9adc2 Fix image link 2018-11-10 10:50:20 +01:00
James Cole
5cc840e390 Verify routine will check currency usage. 2018-11-10 10:50:12 +01:00
James Cole
e491dda229 Currencies can now be enabled and disabled. 2018-11-10 10:04:46 +01:00
James Cole
daa8aa5c9d Fix for #1858 2018-11-09 19:00:24 +01:00
James Cole
0561554726 Bigger sleep cycle, but improve page count to compensate. 2018-11-06 16:51:51 +01:00
James Cole
34abc6490c Fix issue with transaction journal factory. 2018-11-06 05:50:36 +01:00
James Cole
66f309f5ed Clean up debug views. 2018-11-02 21:17:07 +01:00
James Cole
2283f3e786 Fix #1840 2018-11-02 21:16:47 +01:00
James Cole
d261c793ae Add extra cache path. 2018-11-02 20:40:35 +01:00
James Cole
31448a3add Move all layout files to a "v1" directory. 2018-11-02 19:59:29 +01:00
James Cole
d85ccb6ab2 Try to catch a null pointer. 2018-11-02 05:59:22 +01:00
James Cole
bd0be97137 Merge pull request #1848 from kriegalex/feature/swiss-franc
Add swiss franc to currency seeder
2018-11-01 16:06:18 +01:00
Marco Lourenço
81d70a57ca Add swiss franc to currency seeder 2018-11-01 15:15:49 +01:00
James Cole
b17f2f5d1f Improve logging #1607 2018-10-31 16:33:03 +01:00
James Cole
53ed5b2975 Improved logging for bunq routine. #1607 2018-10-31 16:25:21 +01:00
James Cole
5626fee282 Merge tag '4.7.8' into develop
4.7.8
2018-10-28 19:44:37 +01:00
James Cole
cb9aefc489 Merge branch 'release/4.7.8' 2018-10-28 19:44:34 +01:00
James Cole
a9c83beb4f Updated translations. 2018-10-28 19:25:53 +01:00
James Cole
4a64a1bd46 Update meta files for new release. 2018-10-28 19:19:39 +01:00
James Cole
4152179f10 Fix #1830 2018-10-28 19:17:33 +01:00
James Cole
400219a9fc Add iban to mouse over #1715 2018-10-28 16:15:52 +01:00
James Cole
933105a721 Fix #1825 2018-10-28 15:51:11 +01:00
James Cole
bb39781848 Some extra debugging and a fix for #1825 2018-10-28 13:53:00 +01:00
James Cole
f90b7bed5e Remove double exclamation mark. 2018-10-28 13:52:22 +01:00
James Cole
80bf94c009 Updated language strings. 2018-10-28 13:17:15 +01:00
James Cole
f46904c644 Merge pull request #1826 from dennisenderink/bugfix/translate-start-balance-on-opening-asset-account
Bugfix/translate start balance on opening asset account
2018-10-28 13:11:31 +01:00
Dennis Enderink
057619b157 Cast to string because trans() could return array 2018-10-27 23:26:04 +02:00
Dennis Enderink
fd505b77b2 Fixed alignment of some language files 2018-10-27 23:23:54 +02:00
Dennis Enderink
81a23b5b22 Added translation for initial balance account name on creation 2018-10-27 23:20:54 +02:00
James Cole
c0ab0b5af5 Fix tests for current feature set. 2018-10-27 05:39:11 +02:00
James Cole
970cc91938 Fix for #1825 2018-10-27 05:10:49 +02:00
James Cole
749d373c95 New translations [skip ci] 2018-10-26 14:49:19 +02:00
James Cole
3a427dd0f4 Refactor temporary account storage and fix a bug in the bunq import. #1607 2018-10-25 20:03:48 +02:00
James Cole
e1402d5d8a Fix for #1812 2018-10-23 18:56:37 +02:00
James Cole
864a6883d4 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2018-10-23 18:54:31 +02:00
James Cole
9b58c28be8 Fix #1807 2018-10-23 18:53:38 +02:00
James Cole
69fe6ecb7d Merge pull request #1813 from hamuz/develop
Fix remote backing storage
2018-10-23 18:52:48 +02:00
HamuZ HamuZ
321676c97f fix wrong local disk for export, and prefer local to remote 2018-10-23 18:44:12 +03:00
HamuZ HamuZ
d2e1493530 fixate flysystem-fallback-adapter in 0.1.2 (without buggy PR accepted) 2018-10-23 18:36:45 +03:00
James Cole
1c8375d0c2 Fix #1807 2018-10-22 19:00:37 +02:00
James Cole
e164e22e13 Yoda style if statement. 2018-10-21 11:08:54 +02:00
James Cole
c1c4c96918 Keep DB at version 10. 2018-10-21 11:08:45 +02:00
James Cole
742e03944d Small textual changes for #1159 2018-10-21 11:08:36 +02:00
James Cole
60f2c19d9d Clean up env files. 2018-10-21 11:07:19 +02:00
James Cole
21a8d9a109 Merge pull request #1797 from bnw/develop
Parse description from FinTSTransaction
2018-10-21 10:47:34 +02:00
Ben
9abedf3160 Refactored pardsing of description for FinTS import.
Added some tests.
2018-10-20 15:50:53 +02:00
Ben
4e48961c2b Parse description from FinTSTransaction 2018-10-20 14:53:47 +02:00
James Cole
78cd1629de Fix for #1805 2018-10-20 09:16:35 +02:00
James Cole
dd0cc2d173 Updated Docker files and double check the login provider. 2018-10-19 09:51:58 +02:00
James Cole
8f00d2b616 Merge pull request #1800 from hamuz/develop
bills: match attachment route with the icon
2018-10-17 18:14:11 +02:00
HamuZ HamuZ
c26d98b308 bills: match attachment route with icon 2018-10-17 19:07:09 +03:00
James Cole
913774850b Merge pull request #1799 from hamuz/develop
Add links to transaction from dates in bill, closes #1771
2018-10-17 17:47:17 +02:00
HamuZ HamuZ
43c9737e6e Add links to transaction from dates in bill 2018-10-17 18:17:16 +03:00
James Cole
67cd3b6f81 Force InnoDB for MySQL. 2018-10-17 15:50:43 +02:00
James Cole
d0d2189d55 Users can now reorder budgets #1108 2018-10-17 15:18:09 +02:00
James Cole
b12773bc99 Fix for #1784 2018-10-17 06:06:36 +02:00
James Cole
da5a1fe264 Fix for #1785 2018-10-17 06:05:19 +02:00
James Cole
ea48c23535 Fix for #1790 2018-10-17 05:31:51 +02:00
James Cole
8cd0d5e1ef Fix for #1798 2018-10-17 05:04:26 +02:00
James Cole
9b46e62eb6 match api end point with config changes. 2018-10-16 21:42:08 +02:00
James Cole
1653152dad Fix for #1792 2018-10-15 19:37:18 +02:00
James Cole
db7e3d725e Fix for #1781 2018-10-14 17:38:26 +02:00
James Cole
329b34f7d1 Fix for #1760 2018-10-14 16:54:11 +02:00
James Cole
d624f20107 Fixes for #1747 2018-10-14 16:40:12 +02:00
James Cole
20bebeb7de Fix in file system configuration [skip ci] 2018-10-14 16:27:26 +02:00
James Cole
4e9456b33b Make SFTP primary. 2018-10-14 14:49:03 +02:00
James Cole
26c03552c6 Fix for #1159 2018-10-14 14:38:13 +02:00
James Cole
ac6c3496d4 Fix LDAP in Dockerfile. 2018-10-14 11:42:49 +02:00
James Cole
2f1760f358 Sync up config files #1787 2018-10-14 09:05:02 +02:00
James Cole
53db8912d6 Some mild refactoring for #1787 2018-10-14 08:53:00 +02:00
James Cole
91ef21a665 Merge pull request #1787 from hamuz/develop
allow sftp host as backing storage using env
2018-10-14 08:41:40 +02:00
James Cole
5b1153ab65 Considerations on new line. 2018-10-14 08:40:10 +02:00
James Cole
5196bb9281 Remove code climate configuration. 2018-10-14 08:38:11 +02:00
James Cole
8fd6f8177f Update readme. 2018-10-14 08:38:03 +02:00
HamuZ HamuZ
7b68716a3d allow sftp host as backing storage using env 2018-10-14 07:09:00 +03:00
James Cole
d8ecc63e66 Fix Spectre test. 2018-10-13 22:15:06 +02:00
James Cole
2575f61828 Remove test script from root of Firefly III. 2018-10-13 21:45:23 +02:00
James Cole
c6370ebe48 Fix tests for login providers when dealing with LDAP. 2018-10-13 21:45:12 +02:00
James Cole
3bc38570a2 Code for #1071 2018-10-13 21:32:20 +02:00
James Cole
0d36d43eda Initial code for LDAP authentication. 2018-10-13 15:06:56 +02:00
James Cole
a5a012738e Code for #1733 2018-10-13 13:19:41 +02:00
James Cole
7cce6504e3 Merge pull request #1782 from hamuz/develop
fix local references in upload/export disk. first step for #1727.
2018-10-13 09:03:42 +02:00
HamuZ HamuZ
f696353e2c fix local references in upload/export disk. first step for #1727. 2018-10-13 09:56:26 +03:00
James Cole
cf11dfe73b Remove cache for #1778 2018-10-12 07:57:26 +02:00
James Cole
940323c0b7 Small fix in auto complete controller. 2018-10-12 07:39:05 +02:00
James Cole
9f768396c2 Code for #1698 2018-10-10 06:09:25 +02:00
James Cole
160e57bfde Merge pull request #1775 from BoGnY/develop
Fixed locales lang error on Heroku build platform
2018-10-10 06:06:02 +02:00
Luca Bognolo
429bec66f2 Fixed locales lang error on Heroku build platform
Starting from heroku 16 stack the language packs are not included by default: https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-locale

Signed-off-by: Luca Bognolo <git@bogny.eu>
2018-10-09 17:38:23 +02:00
James Cole
7f9b5e1e5e Small updates for Sandstorm release. 2018-10-08 19:54:37 +02:00
James Cole
8088c28235 Solve a problem with inline displaying of file attachments. 2018-10-07 18:41:02 +02:00
James Cole
2ec310da18 Make sure user ID is an integer #1774 2018-10-07 15:55:44 +02:00
James Cole
d8addc3175 Tag controller tests. 2018-10-07 10:46:11 +02:00
James Cole
7887655077 Fix spelling error 2018-10-07 09:46:32 +02:00
James Cole
209c42b316 Re-enable cache on various charts. 2018-10-07 09:46:15 +02:00
James Cole
011d8a2b9a Make stuff scale better #1040 2018-10-07 09:45:50 +02:00
James Cole
6f70791239 Refactoring of code for #1159 2018-10-05 17:54:51 +02:00
James Cole
7ac439fd0e Merge pull request #1770 from bnw/develop
Added a first version of an import via FinTS
2018-10-05 17:34:41 +02:00
Ben
0cda098b4f Don't use deprecated method accountRepository->find 2018-10-05 16:32:29 +02:00
Ben
aaff40c4ad Construct FinTS via service container so it can be mocked 2018-10-05 16:30:05 +02:00
Ben
306e1081e3 Bugfix: array_filter preserves keys, so $filteredAccounts[0] might not exist 2018-10-05 16:19:48 +02:00
James Cole
a1e2dac658 Another fix for #1583 2018-10-04 20:55:04 +02:00
James Cole
07382d5c6d Merge pull request #1765 from mconway/develop
Update PiggyBankRequest.php
2018-10-04 20:08:57 +02:00
James Cole
56fdb57d24 Fix for #1583 2018-10-04 20:06:12 +02:00
Mike Conway
336a9a97f9 Update PiggyBankRequest.php
Fix inconsistencies between repository and request variables
2018-10-03 19:37:16 -07:00
Ben
88083c5b38 Added 'original-source'-field to imported transactions 2018-10-03 14:13:46 +02:00
Ben
7e590fb6b3 Use arbitrary precision math 2018-10-03 14:10:53 +02:00
Ben
4bb4ffbac4 Use Carbon instead of DateTime 2018-10-03 14:05:07 +02:00
Ben
7de3c7f80a Code style 2018-10-03 14:02:06 +02:00
Ben
84d0e44a08 Strict comparison 2018-10-03 13:59:48 +02:00
Ben
d7ca7e4cd8 MessageBag needs messages as array 2018-10-03 13:58:57 +02:00
Ben
3ba41d712f Added import and type hinting 2018-10-03 13:57:17 +02:00
Ben
ce917298ed Store password encrypted 2018-10-03 13:56:53 +02:00
Ben
91e0e33a04 Remove debug 2018-10-03 13:47:38 +02:00
Ben
c32e9fabd9 Bugfix 2018-10-03 13:46:18 +02:00
Ben
dc73db2a07 Added FinTS import 2018-10-03 13:38:09 +02:00
James Cole
89cc01ce44 Merge pull request #1753 from hamuz/patch-4
fix typo in PrependDescription [skip ci]
2018-10-01 07:25:38 +02:00
HamuZ HamuZ
efa3eb1981 fix typo in PrependDescription [skip ci] 2018-10-01 08:21:03 +03:00
James Cole
50ab1fa3f0 Test improvement for import routine. 2018-09-30 20:14:17 +02:00
James Cole
e50641e969 Fix #1751 2018-09-30 19:11:49 +02:00
James Cole
d4c763df84 Fix #1751 2018-09-30 18:41:10 +02:00
James Cole
c0669c158a Update badge to read php 7.2 2018-09-30 12:00:08 +02:00
James Cole
e33bbc6f16 Expand test coverage. 2018-09-30 11:57:51 +02:00
James Cole
ea5ab54c3a Merge pull request #1746 from ms32035/logging_fix
Fix incorrect logging message
2018-09-30 07:54:35 +02:00
Marcin Szymanski
3c18ea1e14 Fix incorrect logging message 2018-09-30 01:07:12 +01:00
James Cole
25ba86b5d8 Merge tag '4.7.7' into develop
4.7.7
2018-09-29 12:27:05 +02:00
1968 changed files with 160821 additions and 30514 deletions

View File

@@ -1,12 +0,0 @@
---
exclude_patterns:
- public/lib/
- public/js/lib/
- public/fonts/
- public/css/jquery-ui/
- public/css/bootstrap-multiselect.css
- public/css/bootstrap-sortable.css
- public/css/bootstrap-tagsinput.css
- public/css/daterangepicker.css
- public/css/google-fonts.css
- .sandstorm/

View File

@@ -1,73 +1,3 @@
# This is the main Apache server configuration file. It contains the
# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.
# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf-enabled
# | `-- *.conf
# `-- sites-enabled
# `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
# together by including all remaining configuration files when starting up the
# web server.
#
# * ports.conf is always included from the main configuration file. It is
# supposed to determine listening ports for incoming connections which can be
# customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
# directories contain particular configuration snippets which manage modules,
# global configuration fragments, or virtual host configurations,
# respectively.
#
# They are activated by symlinking available configuration files from their
# respective *-available/ counterparts. These should be managed by using our
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
# their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
# the default configuration, apache2 needs to be started/stopped with
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
# work with the default configuration.
# Global configuration
#
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"
#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#

18
.deploy/docker/build-amd64.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# build image
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
if [ "$TRAVIS_BRANCH" == "develop" ]; then
echo "Build develop amd64"
docker build -t jc5x/firefly-iii:develop-amd -f Dockerfile.amd64 .
docker push jc5x/firefly-iii:develop-amd
fi
if [ "$TRAVIS_BRANCH" == "master" ]; then
echo "Build master amd64"
docker build -t jc5x/firefly-iii:latest-amd -f Dockerfile.amd64 .
docker tag jc5x/firefly-iii:latest-amd jc5x/firefly-iii:release-$VERSION-amd
docker push jc5x/firefly-iii:latest-amd
docker push jc5x/firefly-iii:release-$VERSION-amd
fi

28
.deploy/docker/build-arm.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
docker run --rm --privileged multiarch/qemu-user-static:register --reset
# get qemu-arm-static binary
mkdir tmp
pushd tmp && \
curl -L -o qemu-arm-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/v2.6.0/qemu-arm-static.tar.gz && \
tar xzf qemu-arm-static.tar.gz && \
popd
# build image
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
if [ "$TRAVIS_BRANCH" == "develop" ]; then
echo "Build develop arm"
docker build --tag jc5x/firefly-iii:develop-arm --file Dockerfile.arm .
docker push jc5x/firefly-iii:develop-arm
fi
if [ "$TRAVIS_BRANCH" == "master" ]; then
echo "Build master arm"
docker build --tag jc5x/firefly-iii:latest-arm --file Dockerfile.arm .
docker tag jc5x/firefly-iii:latest-arm jc5x/firefly-iii:release-$VERSION-arm
docker push jc5x/firefly-iii:latest-arm
docker push jc5x/firefly-iii:release-$VERSION-arm
fi

3314
.deploy/docker/cacert.pem Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,6 +0,0 @@
FF_APP_ENV=local
FF_APP_KEY=S0m3R@nd0mString0f32Ch@rsEx@ct1y
FF_DB_HOST=
FF_DB_NAME=
FF_DB_USER=
FF_DB_PASSWORD=

View File

@@ -1,29 +1,64 @@
#!/bin/bash
echo "Now in entrypoint.sh for Firefly III"
lscpu
# make sure the correct directories exists (suggested by @chrif):
mkdir -p $FIREFLY_PATH/storage/app
echo "Making directories..."
mkdir -p $FIREFLY_PATH/storage/app/public
mkdir -p $FIREFLY_PATH/storage/build
mkdir -p $FIREFLY_PATH/storage/database
mkdir -p $FIREFLY_PATH/storage/debugbar
mkdir -p $FIREFLY_PATH/storage/export
mkdir -p $FIREFLY_PATH/storage/framework/cache
mkdir -p $FIREFLY_PATH/storage/framework/cache/data
mkdir -p $FIREFLY_PATH/storage/framework/sessions
mkdir -p $FIREFLY_PATH/storage/framework/testing
mkdir -p $FIREFLY_PATH/storage/framework/views
mkdir -p $FIREFLY_PATH/storage/framework/views/v1
mkdir -p $FIREFLY_PATH/storage/framework/views/v2
mkdir -p $FIREFLY_PATH/storage/logs
mkdir -p $FIREFLY_PATH/storage/upload
echo "Touch DB file (if SQLlite)..."
if [[ $DB_CONNECTION == "sqlite" ]]
then
touch $FIREFLY_PATH/storage/database/database.sqlite
echo "Touched!"
fi
if [[ $FF_DB_CONNECTION == "sqlite" ]]
then
touch $FIREFLY_PATH/storage/database/database.sqlite
echo "Touched!"
fi
# make sure we own the volumes:
echo "Run chown on ${FIREFLY_PATH}/storage..."
chown -R www-data:www-data -R $FIREFLY_PATH/storage
echo "Run chmod on ${FIREFLY_PATH}/storage..."
chmod -R 775 $FIREFLY_PATH/storage
# remove any lingering files that may break upgrades:
echo "Remove log file..."
rm -f $FIREFLY_PATH/storage/logs/laravel.log
echo "Map environment variables on .env file..."
cat .env.docker | envsubst > .env
echo "Dump auto load..."
composer dump-autoload
echo "Discover packages..."
php artisan package:discover
echo "Run various artisan commands..."
php artisan migrate --seed
php artisan firefly:decrypt-all
php artisan firefly:upgrade-database
php artisan firefly:verify
php artisan passport:install
php artisan cache:clear
php artisan firefly:instructions install
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf --nodaemon
echo "Go!"
exec apache2-foreground

View File

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

35
.deploy/docker/manifest.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
if [ "$TRAVIS_BRANCH" == "develop" ]; then
TARGET=jc5x/firefly-iii:develop
ARM=jc5x/firefly-iii:develop-arm
AMD=jc5x/firefly-iii:develop-amd64
docker manifest create $TARGET $AMD $ARM
docker manifest annotate $TARGET $ARM --arch arm --os linux
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
docker manifest push $TARGET
fi
echo "The version is $VERSION"
if [ "$TRAVIS_BRANCH" == "master" ]; then
TARGET=jc5x/firefly-iii:latest
ARM=jc5x/firefly-iii:latest-arm
AMD=jc5x/firefly-iii:latest-amd64
docker manifest create $TARGET $AMD $ARM
docker manifest annotate $TARGET $ARM --arch arm --os linux
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
docker manifest push $TARGET
# and another one for version specific:
TARGET=jc5x/firefly-iii:release-$VERSION
ARM=jc5x/firefly-iii:release-$VERSION-arm
AMD=jc5x/firefly-iii:release-$VERSION-amd64
docker manifest create $TARGET $AMD $ARM
docker manifest annotate $TARGET $ARM --arch arm --os linux
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
docker manifest push $TARGET
fi

View File

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

View File

@@ -43,12 +43,25 @@ DB_HOST=${FF_DB_HOST}
DB_PORT=${FF_DB_PORT}
DB_DATABASE=${FF_DB_NAME}
DB_USERNAME=${FF_DB_USER}
DB_PASSWORD=${FF_DB_PASSWORD}
DB_PASSWORD="${FF_DB_PASSWORD}"
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
SESSION_DRIVER=file
# You can configure another file storage backend if you cannot use the local storage option.
# To set this up, fill in the following variables. The upload path is used to store uploaded
# files and the export path is to store exported data (before download).
SFTP_HOST=${SFTP_HOST}
SFTP_PORT=${SFTP_PORT}
SFTP_UPLOAD_PATH=${SFTP_UPLOAD_PATH}
SFTP_EXPORT_PATH=${SFTP_EXPORT_PATH}
# SFTP uses either the username/password combination or the private key to authenticate.
SFTP_USERNAME=${SFTP_USERNAME}
SFTP_PASSWORD="${SFTP_PASSWORD}"
SFTP_PRIV_KEY=${SFTP_PRIV_KEY}
# Cookie settings. Should not be necessary to change these.
COOKIE_PATH="/"
COOKIE_DOMAIN=
@@ -61,7 +74,7 @@ MAIL_HOST=${MAIL_HOST}
MAIL_PORT=${MAIL_PORT}
MAIL_FROM=${MAIL_FROM}
MAIL_USERNAME=${MAIL_USERNAME}
MAIL_PASSWORD=${MAIL_PASSWORD}
MAIL_PASSWORD="${MAIL_PASSWORD}"
MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
# Other mail drivers:
@@ -74,11 +87,20 @@ SPARKPOST_SECRET=${SPARKPOST_SECRET}
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=false
# These messages contain (sensitive) transaction information:
SEND_REPORT_JOURNALS=${SEND_REPORT_JOURNALS}
# 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}
# 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
# Firefly III currently supports two provider for live Currency Exchange Rates:
# "fixer" is the default (for backward compatibility), and "ratesapi" is the new one.
# RatesApi.IO (see https://ratesapi.io) is a FREE and OPEN SOURCE live currency exchange rates,
# built compatible with Fixer.IO, based on data published by European Central Bank, and don't require API key.
CER_PROVIDER=${CER_PROVIDER}
# If you have select "fixer" as default currency exchange rates,
# 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 severely limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=${FIXER_API_KEY}
@@ -89,9 +111,55 @@ ANALYTICS_ID=${ANALYTICS_ID}
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
USE_ENCRYPTION=true
# Firefly III has two options for user authentication. "eloquent" is the default,
# and "adldap" for LDAP servers.
# For full instructions on these settings please visit:
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
LOGIN_PROVIDER=${LOGIN_PROVIDER}
# LDAP connection configuration
ADLDAP_CONNECTION_SCHEME=${ADLDAP_CONNECTION_SCHEME}
ADLDAP_AUTO_CONNECT=${ADLDAP_AUTO_CONNECT}
# LDAP connection settings
ADLDAP_CONTROLLERS=${ADLDAP_CONTROLLERS}
ADLDAP_PORT=${ADLDAP_PORT}
ADLDAP_TIMEOUT=${ADLDAP_TIMEOUT}
ADLDAP_BASEDN="${ADLDAP_BASEDN}"
ADLDAP_FOLLOW_REFFERALS=${ADLDAP_FOLLOW_REFFERALS}
ADLDAP_USE_SSL=${ADLDAP_USE_SSL}
ADLDAP_USE_TLS=${ADLDAP_USE_TLS}
ADLDAP_ADMIN_USERNAME=${ADLDAP_ADMIN_USERNAME}
ADLDAP_ADMIN_PASSWORD="${ADLDAP_ADMIN_PASSWORD}"
ADLDAP_ACCOUNT_PREFIX="${ADLDAP_ACCOUNT_PREFIX}"
ADLDAP_ACCOUNT_SUFFIX="${ADLDAP_ACCOUNT_SUFFIX}"
ADLDAP_ADMIN_ACCOUNT_PREFIX="${ADLDAP_ADMIN_ACCOUNT_PREFIX}"
ADLDAP_ADMIN_ACCOUNT_SUFFIX="${ADLDAP_ADMIN_ACCOUNT_SUFFIX}"
# LDAP authentication settings.
ADLDAP_PASSWORD_SYNC=${ADLDAP_PASSWORD_SYNC}
ADLDAP_LOGIN_FALLBACK=${ADLDAP_LOGIN_FALLBACK}
ADLDAP_DISCOVER_FIELD=${ADLDAP_DISCOVER_FIELD}
ADLDAP_AUTH_FIELD=${ADLDAP_AUTH_FIELD}
# Will allow SSO if your server provides an AUTH_USER field.
WINDOWS_SSO_DISCOVER=${WINDOWS_SSO_DISCOVER}
WINDOWS_SSO_KEY=${WINDOWS_SSO_KEY}
# field to sync as local username.
ADLDAP_SYNC_FIELD=${ADLDAP_SYNC_FIELD}
# You can disable the X-Frame-Options header if it interfears with tools like
# Organizr. This is at your own risk.
DISABLE_FRAME_HEADER=${DISABLE_FRAME_HEADER}
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII
ADLDAP_CONNECTION=default
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
@@ -108,5 +176,4 @@ IS_DOCKER=true
IS_SANDSTORM=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=
FFIII_LAYOUT=v1

View File

@@ -49,6 +49,19 @@ DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
# You can configure another file storage backend if you cannot use the local storage option.
# To set this up, fill in the following variables. The upload path is used to store uploaded
# files and the export path is to store exported data (before download).
SFTP_HOST=
SFTP_PORT=
SFTP_UPLOAD_PATH=
SFTP_EXPORT_PATH=
# SFTP uses either the username/password combination or the private key to authenticate.
SFTP_USERNAME=
SFTP_PASSWORD=
SFTP_PRIV_KEY=
# Cookie settings. Should not be necessary to change these.
COOKIE_PATH="/"
COOKIE_DOMAIN=
@@ -74,11 +87,20 @@ SPARKPOST_SECRET=
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
# These messages contain (sensitive) transaction information:
SEND_REPORT_JOURNALS=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
# Firefly III currently supports two provider for live Currency Exchange Rates:
# "fixer" is the default (for backward compatibility), and "ratesapi" is the new one.
# RatesApi.IO (see https://ratesapi.io) is a FREE and OPEN SOURCE live currency exchange rates,
# built compatible with Fixer.IO, based on data published by European Central Bank, and don't require API key.
CER_PROVIDER=fixer
# If you have select "fixer" as default currency exchange rates,
# 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 severely limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
@@ -89,9 +111,56 @@ ANALYTICS_ID=
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
USE_ENCRYPTION=true
# Firefly III has two options for user authentication. "eloquent" is the default,
# and "adldap" for LDAP servers.
# For full instructions on these settings please visit:
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
LOGIN_PROVIDER=eloquent
# LDAP connection configuration
# OpenLDAP, FreeIPA or ActiveDirectory
ADLDAP_CONNECTION_SCHEME=OpenLDAP
ADLDAP_AUTO_CONNECT=true
# LDAP connection settings
ADLDAP_CONTROLLERS=
ADLDAP_PORT=389
ADLDAP_TIMEOUT=5
ADLDAP_BASEDN=""
ADLDAP_FOLLOW_REFFERALS=false
ADLDAP_USE_SSL=false
ADLDAP_USE_TLS=false
ADLDAP_ADMIN_USERNAME=
ADLDAP_ADMIN_PASSWORD=
ADLDAP_ACCOUNT_PREFIX=
ADLDAP_ACCOUNT_SUFFIX=
ADLDAP_ADMIN_ACCOUNT_PREFIX=
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
# LDAP authentication settings.
ADLDAP_PASSWORD_SYNC=false
ADLDAP_LOGIN_FALLBACK=false
ADLDAP_DISCOVER_FIELD=distinguishedname
ADLDAP_AUTH_FIELD=distinguishedname
# Will allow SSO if your server provides an AUTH_USER field.
WINDOWS_SSO_DISCOVER=samaccountname
WINDOWS_SSO_KEY=AUTH_USER
# field to sync as local username.
ADLDAP_SYNC_FIELD=userprincipalname
# You can disable the X-Frame-Options header if it interfears with tools like
# Organizr. This is at your own risk.
DISABLE_FRAME_HEADER=false
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII
ADLDAP_CONNECTION=default
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
@@ -108,5 +177,4 @@ IS_DOCKER=false
IS_SANDSTORM=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=
FFIII_LAYOUT=v1

View File

@@ -49,6 +49,19 @@ DB_CONNECTION=pgsql
CACHE_DRIVER=file
SESSION_DRIVER=file
# You can configure another file storage backend if you cannot use the local storage option.
# To set this up, fill in the following variables. The upload path is used to store uploaded
# files and the export path is to store exported data (before download).
SFTP_HOST=
SFTP_PORT=
SFTP_UPLOAD_PATH=
SFTP_EXPORT_PATH=
# SFTP uses either the username/password combination or the private key to authenticate.
SFTP_USERNAME=
SFTP_PASSWORD=
SFTP_PRIV_KEY=
# Cookie settings. Should not be necessary to change these.
COOKIE_PATH="/"
COOKIE_DOMAIN=
@@ -74,11 +87,20 @@ SPARKPOST_SECRET=
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
# These messages contain (sensitive) transaction information:
SEND_REPORT_JOURNALS=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
# Firefly III currently supports two provider for live Currency Exchange Rates:
# "fixer" is the default (for backward compatibility), and "ratesapi" is the new one.
# RatesApi.IO (see https://ratesapi.io) is a FREE and OPEN SOURCE live currency exchange rates,
# built compatible with Fixer.IO, based on data published by European Central Bank, and don't require API key.
CER_PROVIDER=fixer
# If you have select "fixer" as default currency exchange rates,
# 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 severely limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
@@ -89,9 +111,56 @@ ANALYTICS_ID=
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
USE_ENCRYPTION=true
# Firefly III has two options for user authentication. "eloquent" is the default,
# and "adldap" for LDAP servers.
# For full instructions on these settings please visit:
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
LOGIN_PROVIDER=eloquent
# LDAP connection configuration
# OpenLDAP, FreeIPA or ActiveDirectory
ADLDAP_CONNECTION_SCHEME=OpenLDAP
ADLDAP_AUTO_CONNECT=true
# LDAP connection settings
ADLDAP_CONTROLLERS=
ADLDAP_PORT=389
ADLDAP_TIMEOUT=5
ADLDAP_BASEDN=""
ADLDAP_FOLLOW_REFFERALS=false
ADLDAP_USE_SSL=false
ADLDAP_USE_TLS=false
ADLDAP_ADMIN_USERNAME=
ADLDAP_ADMIN_PASSWORD=
ADLDAP_ACCOUNT_PREFIX=
ADLDAP_ACCOUNT_SUFFIX=
ADLDAP_ADMIN_ACCOUNT_PREFIX=
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
# LDAP authentication settings.
ADLDAP_PASSWORD_SYNC=false
ADLDAP_LOGIN_FALLBACK=false
ADLDAP_DISCOVER_FIELD=distinguishedname
ADLDAP_AUTH_FIELD=distinguishedname
# Will allow SSO if your server provides an AUTH_USER field.
WINDOWS_SSO_DISCOVER=samaccountname
WINDOWS_SSO_KEY=AUTH_USER
# field to sync as local username.
ADLDAP_SYNC_FIELD=userprincipalname
# You can disable the X-Frame-Options header if it interfears with tools like
# Organizr. This is at your own risk.
DISABLE_FRAME_HEADER=false
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII
ADLDAP_CONNECTION=default
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
@@ -108,5 +177,4 @@ IS_DOCKER=false
IS_SANDSTORM=false
IS_HEROKU=true
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=
FFIII_LAYOUT=v1

View File

@@ -3,7 +3,7 @@
APP_ENV=local
# Set to true if you want to see debug information in error screens.
APP_DEBUG=false
APP_DEBUG=true
# This should be your email address
SITE_OWNER=sandstorm@example.com
@@ -49,6 +49,19 @@ DB_PASSWORD=firefly
CACHE_DRIVER=file
SESSION_DRIVER=file
# You can configure another file storage backend if you cannot use the local storage option.
# To set this up, fill in the following variables. The upload path is used to store uploaded
# files and the export path is to store exported data (before download).
SFTP_HOST=
SFTP_PORT=
SFTP_UPLOAD_PATH=
SFTP_EXPORT_PATH=
# SFTP uses either the username/password combination or the private key to authenticate.
SFTP_USERNAME=
SFTP_PASSWORD=
SFTP_PRIV_KEY=
# Cookie settings. Should not be necessary to change these.
COOKIE_PATH="/"
COOKIE_DOMAIN=
@@ -74,11 +87,20 @@ SPARKPOST_SECRET=
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
# These messages contain (sensitive) transaction information:
SEND_REPORT_JOURNALS=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
# Firefly III currently supports two provider for live Currency Exchange Rates:
# "fixer" is the default (for backward compatibility), and "ratesapi" is the new one.
# RatesApi.IO (see https://ratesapi.io) is a FREE and OPEN SOURCE live currency exchange rates,
# built compatible with Fixer.IO, based on data published by European Central Bank, and don't require API key.
CER_PROVIDER=fixer
# If you have select "fixer" as default currency exchange rates,
# 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 severely limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
@@ -89,9 +111,56 @@ ANALYTICS_ID=
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
USE_ENCRYPTION=true
# Firefly III has two options for user authentication. "eloquent" is the default,
# and "adldap" for LDAP servers.
# For full instructions on these settings please visit:
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
LOGIN_PROVIDER=eloquent
# LDAP connection configuration
# or FreeIPA or ActiveDirectory
ADLDAP_CONNECTION_SCHEME=OpenLDAP
ADLDAP_AUTO_CONNECT=true
# LDAP connection settings
ADLDAP_CONTROLLERS=
ADLDAP_PORT=389
ADLDAP_TIMEOUT=5
ADLDAP_BASEDN=""
ADLDAP_FOLLOW_REFFERALS=false
ADLDAP_USE_SSL=false
ADLDAP_USE_TLS=false
ADLDAP_ADMIN_USERNAME=
ADLDAP_ADMIN_PASSWORD=
ADLDAP_ACCOUNT_PREFIX=
ADLDAP_ACCOUNT_SUFFIX=
ADLDAP_ADMIN_ACCOUNT_PREFIX=
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
# LDAP authentication settings.
ADLDAP_PASSWORD_SYNC=false
ADLDAP_LOGIN_FALLBACK=false
ADLDAP_DISCOVER_FIELD=distinguishedname
ADLDAP_AUTH_FIELD=distinguishedname
# Will allow SSO if your server provides an AUTH_USER field.
WINDOWS_SSO_DISCOVER=samaccountname
WINDOWS_SSO_KEY=AUTH_USER
# field to sync as local username.
ADLDAP_SYNC_FIELD=userprincipalname
# You can disable the X-Frame-Options header if it interfears with tools like
# Organizr. This is at your own risk.
DISABLE_FRAME_HEADER=true
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII
ADLDAP_CONNECTION=default
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
@@ -108,5 +177,4 @@ IS_DOCKER=false
IS_SANDSTORM=true
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=
FFIII_LAYOUT=v1

View File

@@ -49,6 +49,19 @@ DB_CONNECTION=sqlite
CACHE_DRIVER=file
SESSION_DRIVER=file
# You can configure another file storage backend if you cannot use the local storage option.
# To set this up, fill in the following variables. The upload path is used to store uploaded
# files and the export path is to store exported data (before download).
SFTP_HOST=
SFTP_PORT=
SFTP_UPLOAD_PATH=
SFTP_EXPORT_PATH=
# SFTP uses either the username/password combination or the private key to authenticate.
SFTP_USERNAME=
SFTP_PASSWORD=
SFTP_PRIV_KEY=
# Cookie settings. Should not be necessary to change these.
COOKIE_PATH="/"
COOKIE_DOMAIN=
@@ -74,11 +87,20 @@ SPARKPOST_SECRET=
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=false
# These messages contain (sensitive) transaction information:
SEND_REPORT_JOURNALS=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
# Firefly III currently supports two provider for live Currency Exchange Rates:
# "fixer" is the default (for backward compatibility), and "ratesapi" is the new one.
# RatesApi.IO (see https://ratesapi.io) is a FREE and OPEN SOURCE live currency exchange rates,
# built compatible with Fixer.IO, based on data published by European Central Bank, and don't require API key.
CER_PROVIDER=fixer
# If you have select "fixer" as default currency exchange rates,
# 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 severely limited
# the free API up to the point where you might as well offer nothing.
FIXER_API_KEY=
@@ -89,9 +111,56 @@ ANALYTICS_ID=
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
USE_ENCRYPTION=false
# Firefly III has two options for user authentication. "eloquent" is the default,
# and "adldap" for LDAP servers.
# For full instructions on these settings please visit:
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
LOGIN_PROVIDER=eloquent
# LDAP connection configuration
# or FreeIPA or ActiveDirectory
ADLDAP_CONNECTION_SCHEME=OpenLDAP
ADLDAP_AUTO_CONNECT=true
# LDAP connection settings
ADLDAP_CONTROLLERS=
ADLDAP_PORT=389
ADLDAP_TIMEOUT=5
ADLDAP_BASEDN=""
ADLDAP_FOLLOW_REFFERALS=false
ADLDAP_USE_SSL=false
ADLDAP_USE_TLS=false
ADLDAP_ADMIN_USERNAME=
ADLDAP_ADMIN_PASSWORD=
ADLDAP_ACCOUNT_PREFIX=
ADLDAP_ACCOUNT_SUFFIX=
ADLDAP_ADMIN_ACCOUNT_PREFIX=
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
# LDAP authentication settings.
ADLDAP_PASSWORD_SYNC=false
ADLDAP_LOGIN_FALLBACK=false
ADLDAP_DISCOVER_FIELD=distinguishedname
ADLDAP_AUTH_FIELD=distinguishedname
# Will allow SSO if your server provides an AUTH_USER field.
WINDOWS_SSO_DISCOVER=samaccountname
WINDOWS_SSO_KEY=AUTH_USER
# field to sync as local username.
ADLDAP_SYNC_FIELD=userprincipalname
# You can disable the X-Frame-Options header if it interfears with tools like
# Organizr. This is at your own risk.
DISABLE_FRAME_HEADER=false
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII
ADLDAP_CONNECTION=default
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
@@ -108,5 +177,4 @@ IS_DOCKER=false
IS_SANDSTORM=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=true
MAILGUN_DOMAIN=
MAILGUN_SECRET=
FFIII_LAYOUT=v1

View File

@@ -5,21 +5,23 @@ about: Create a report to help Firefly III improve
---
**Bug description**
I am running Firefly III version x.x.x
I am running Firefly III version x.x.x, and my problem is:
(please give a clear and concise description of what the bug is)
<!-- Replace the version and describe your problem or your issue will be closed. -->
**Steps to reproduce**
What do you need to do to trigger this bug?
<!-- What do you need to do to trigger this bug? -->
**Expected behavior**
What do you expect to see after those steps?
<!-- What do you expect to see after those steps? -->
**Extra info**
Please add extra info here, such as OS, browser, and the output from the /debug page of your Firefly III installation (click the version at the bottom).
<!-- Please add extra info here, such as OS, browser, and the output from the /debug page of your Firefly III installation (click the version at the bottom). -->
**Bonus points**
Earn bonus points by:
<!-- Earn bonus points by:
- Post a stacktrace from your log files
- Add a screenshot
- Remember the human
-->

View File

@@ -7,21 +7,19 @@ about: Ask away!
I am running Firefly III version x.x.x
**Description**
**Steps to reproduce**
(if relevant of course)
<!-- (if relevant of course) -->
**Extra info**
Please add extra info here, such as OS, browser, and the output from the `/debug`-page of your Firefly III installation (click the version at the bottom).
<!-- Please add extra info here, such as OS, browser, and the output from the `/debug`-page of your Firefly III installation (click the version at the bottom). -->
**Bonus points**
Earn bonus points by:
<!-- Earn bonus points by:
- Add a screenshot
- Replicate the problem on the demo site https://demo.firefly-iii.org/
- Make a drawing
- Donate money (just kidding ;)
- Replicate the problem on the demo site https://demo.firefly-iii.org/
- Remember the human
-->

View File

@@ -5,17 +5,28 @@ about: Suggest an idea or feature for Firefly III
---
**Description**
<!--
Please describe your feature request:
- I would like Firefly III to do X.
- What if you would add feature Y?
- Firefly III doesn't do Z.
- I would like Firefly III to do ABC.
- What if you would add feature XYZ?
- Firefly III doesn't do DEF.
-->
**Solution**
Describe what your feature would add to Firefly III.
<!-- Describe what your feature would add to Firefly III. -->
**What are alternatives?**
Please describe what alternatives currently exist.
<!-- Please describe what alternatives currently exist. -->
**Additional context**
Add any other context or screenshots about the feature request here.
<!-- Add any other context or screenshots about the feature request here. -->
**Bonus points**
<!-- Earn bonus points by:
- Make a drawing
- Donate money (just kidding ;)
- Remember the human
-->

View File

@@ -1,4 +1,11 @@
Fixes # (if relevant)
<!--
Please read me:
1) DO NOT create a pull request for the MASTER branch.
2) DO NOT create pull requests to add new CURRENCIES.
-->
Fixes issue # (if relevant)
Changes in this pull request:

6
.github/stale.yml vendored
View File

@@ -1,7 +1,7 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 14
daysUntilStale: 7
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
@@ -13,6 +13,8 @@ exemptLabels:
- enhancement
- feature
- bug
- possible-bug
- announcement
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
@@ -53,4 +55,4 @@ limitPerRun: 30
# issues:
# exemptLabels:
# - confirmed
# - confirmed

9
.locales Normal file
View File

@@ -0,0 +1,9 @@
en_US
de_DE
fr_FR
it_IT
nl_NL
pl_PL
pt_BR
ru_RU
tr_TR

View File

@@ -1,3 +1,134 @@
# 4.7.11
- Experimental audit logging channel to track important events (separate from debug logging).
- [Issue 2003](https://github.com/firefly-iii/firefly-iii/issues/2003), [issue 2006](https://github.com/firefly-iii/firefly-iii/issues/2006) Transactions can be stored with a timestamp. The user-interface does not support this yet. But the API does.
- Docker image tags a new manifest for arm and amd64.
- [skuzzle](https://github.com/skuzzle) removed an annoying console.log statement.
- [Issue 2048](https://github.com/firefly-iii/firefly-iii/issues/2048) Fix "Are you sure?" popup, thanks to @nescafe2002!
- [Issue 2049](https://github.com/firefly-iii/firefly-iii/issues/2049) Empty preferences would crash Firefly III.
- [Issue 2052](https://github.com/firefly-iii/firefly-iii/issues/2052) Rules could not auto-covert to liabilities.
- Webbased upgrade routine will also decrypt the database.
- Last use date for categories was off.
- The `date`-field in any transaction object now returns a ISO 8601 timestamp instead of a date.
# 4.7.10
- [Issue 2037](https://github.com/firefly-iii/firefly-iii/issues/2037) Added some new magic keywords to reports.
- Added a new currency exchange rate service, [ratesapi.io](https://ratesapi.io/), that does not require expensive API keys. Built by [@BoGnY](https://github.com/BoGnY).
- Added Chinese Traditional translations. Thanks!
- [Issue 1977](https://github.com/firefly-iii/firefly-iii/issues/1977) Docker image now includes memcached support
- [Issue 2031](https://github.com/firefly-iii/firefly-iii/issues/2031) A new generic debit/credit indicator for imports.
- The new Docker image no longer has the capability to run cron jobs, and will no longer generate your recurring transactions for you. This has been done to simplify the build and make sure your Docker container runs one service, as it should. To set up a cron job for your new Docker container, [check out the documentation](https://docs.firefly-iii.org/en/latest/installation/cronjob.html).
- Due to a change in the database structure, this upgrade will reset your preferences. Sorry about that.
- I will no longer accept PR's that introduce new currencies.
- Firefly III no longer encrypts the database and will [decrypt the database]() on its first run.
- [Issue 1923](https://github.com/firefly-iii/firefly-iii/issues/1923) Broken window position for date picker.
- [Issue 1967](https://github.com/firefly-iii/firefly-iii/issues/1967) Attachments were hidden in bill view.
- [Issue 1927](https://github.com/firefly-iii/firefly-iii/issues/1927) It was impossible to make recurring transactions skip.
- [Issue 1929](https://github.com/firefly-iii/firefly-iii/issues/1929) Fix the recurring transactions calendar overview.
- [Issue 1933](https://github.com/firefly-iii/firefly-iii/issues/1933) Fixed a bug that made it impossible to authenticate to FreeIPA servers.
- [Issue 1938](https://github.com/firefly-iii/firefly-iii/issues/1938) The importer can now handle the insane way Postbank (DE) formats its numbers.
- [Issue 1942](https://github.com/firefly-iii/firefly-iii/issues/1942) Favicons are relative so Scriptaculous installations work better.
- [Issue 1944](https://github.com/firefly-iii/firefly-iii/issues/1944) Make sure that the search allows you to mass-select transactions.
- [Issue 1945](https://github.com/firefly-iii/firefly-iii/issues/1945) Slight UI change so the drop-down menu renders better.
- [Issue 1955](https://github.com/firefly-iii/firefly-iii/issues/1955) Fixed a bug in the category report.
- [Issue 1968](https://github.com/firefly-iii/firefly-iii/issues/1968) The yearly range would jump to 1-Jan / 1-Jan instead of 1-Jan / 31-Dec
- [Issue 1975](https://github.com/firefly-iii/firefly-iii/issues/1975) Fixed explanation for missing credit card liabilities.
- [Issue 1979](https://github.com/firefly-iii/firefly-iii/issues/1979) Make sure tags are trimmed.
- [Issue 1983](https://github.com/firefly-iii/firefly-iii/issues/1983) Could not use your favorite decimal separator.
- [Issue 1989](https://github.com/firefly-iii/firefly-iii/issues/1989) Bug in YNAB importer forced you to select all accounts.
- [Issue 1990](https://github.com/firefly-iii/firefly-iii/issues/1990) Rule description was invisible in edit screen.
- [Issue 1996](https://github.com/firefly-iii/firefly-iii/issues/1996) Deleted budget would inadvertently also hide transactions.
- [Issue 2001](https://github.com/firefly-iii/firefly-iii/issues/2001) Various issues with tag chart view.
- [Issue 2009](https://github.com/firefly-iii/firefly-iii/issues/2009) Could not change recurrence back to "forever".
- [Issue 2033](https://github.com/firefly-iii/firefly-iii/issues/2033) Longitude can go from -180 to 180.
- [Issue 2034](https://github.com/firefly-iii/firefly-iii/issues/2034) Rules were not being triggered in mass-edit.
- #2043 In rare instances the repetition of a recurring transaction was displayed incorrectly.
- Fixed broken translations in the recurring transactions overview.
- When you create a recurring transfer you make make it fill (or empty) a piggy bank. This was not working, despite a fix in 4.7.8.
- Fixed a bug where the importer would not be capable of creating new currencies.
- Rule trigger tester would skip the amount.
- OAuth2 form can now submit back to original requester.
- Submitting transactions with a disabled currency will auto-enable the currency.
- The documentation now states that "Deposit" is a possible return when you get a transaction.
- "savingAsset" was incorrectly documented as "savingsAsset".
- Account endpoint can now return type "reconciliation" and "initial-balance" correctly.
- New API endpoint under `/summary/basic` that gives you a basic overview of the user's finances.
- New API endpoints under `/chart/*` to allow you to render charts.
- `/accounts/x/transactions` now supports the limit query parameter.
- `/budgets/x/transactions` now supports the limit query parameter.
- `/available_budgets` now supports custom start and end date parameters.
- New endpoint `/preferences/prefName` to retrieve a single preference.
- Added field `account_name` to all piggy banks.
- New tag cloud in API.
# 4.7.9
- [Issue 1622](https://github.com/firefly-iii/firefly-iii/issues/1622) Can now unlink a transaction from a bill.
- [Issue 1848](https://github.com/firefly-iii/firefly-iii/issues/1848) Added support for the Swiss Franc.
- [Issue 1828](https://github.com/firefly-iii/firefly-iii/issues/1828) Focus on fields for easy access.
- [Issue 1859](https://github.com/firefly-iii/firefly-iii/issues/1859) Warning when seeding database.
- Completely rewritten API. Check out the documentation [here](https://api-docs.firefly-iii.org/).
- Currencies can now be enabled and disabled, making for cleaner views.
- You can disable the `X-Frame-Options` header if this is necessary.
- New fancy favicons.
- Updated and improved docker build.
- Docker build no longer builds its own cURL.
- [Issue 1607](https://github.com/firefly-iii/firefly-iii/issues/1607) [issue 1857](https://github.com/firefly-iii/firefly-iii/issues/1857) [issue 1895](https://github.com/firefly-iii/firefly-iii/issues/1895) Improved bunq import and added support for auto-savings.
- [Issue 1766](https://github.com/firefly-iii/firefly-iii/issues/1766) Extra commands so cache dir is owned by www user.
- [Issue 1811](https://github.com/firefly-iii/firefly-iii/issues/1811) 404 when generating report without options.
- [Issue 1835](https://github.com/firefly-iii/firefly-iii/issues/1835) Strange debug popup removed.
- [Issue 1840](https://github.com/firefly-iii/firefly-iii/issues/1840) Error when exporting data.
- [Issue 1857](https://github.com/firefly-iii/firefly-iii/issues/1857) Bunq import words again (see above).
- [Issue 1858](https://github.com/firefly-iii/firefly-iii/issues/1858) SQL errors when importing CSV.
- [Issue 1861](https://github.com/firefly-iii/firefly-iii/issues/1861) Period navigator was broken.
- [Issue 1864](https://github.com/firefly-iii/firefly-iii/issues/1864) First description was empty on split transactions.
- [Issue 1865](https://github.com/firefly-iii/firefly-iii/issues/1865) Bad math when showing categories.
- [Issue 1868](https://github.com/firefly-iii/firefly-iii/issues/1868) Fixes to FinTS import.
- [Issue 1872](https://github.com/firefly-iii/firefly-iii/issues/1872) Some images had 404's.
- [Issue 1877](https://github.com/firefly-iii/firefly-iii/issues/1877) Several encryption / decryption issues.
- [Issue 1878](https://github.com/firefly-iii/firefly-iii/issues/1878) Wrong nav links
- [Issue 1884](https://github.com/firefly-iii/firefly-iii/issues/1884) Budget API improvements (see above)
- [Issue 1888](https://github.com/firefly-iii/firefly-iii/issues/1888) Transaction API improvements (see above)
- [Issue 1890](https://github.com/firefly-iii/firefly-iii/issues/1890) Fixes in Bills API
- [Issue 1891](https://github.com/firefly-iii/firefly-iii/issues/1891) Typo fixed.
- [Issue 1893](https://github.com/firefly-iii/firefly-iii/issues/1893) Update piggies from recurring transactions.
- [Issue 1898](https://github.com/firefly-iii/firefly-iii/issues/1898) Bug in tag report.
- [Issue 1901](https://github.com/firefly-iii/firefly-iii/issues/1901) Redirect when cloning transactions.
- [Issue 1909](https://github.com/firefly-iii/firefly-iii/issues/1909) Date range fixes.
- [Issue 1916](https://github.com/firefly-iii/firefly-iii/issues/1916) Date range fixes.
# 4.7.8
- [Issue 1005](https://github.com/firefly-iii/firefly-iii/issues/1005) You can now configure Firefly III to use LDAP.
- [Issue 1071](https://github.com/firefly-iii/firefly-iii/issues/1071) You can execute transaction rules using the command line (so you can cronjob it)
- [Issue 1108](https://github.com/firefly-iii/firefly-iii/issues/1108) You can now reorder budgets.
- [Issue 1159](https://github.com/firefly-iii/firefly-iii/issues/1159) The ability to import transactions from FinTS-enabled banks.
- [Issue 1727](https://github.com/firefly-iii/firefly-iii/issues/1727) You can now use SFTP as storage for uploads and exports.
- [Issue 1733](https://github.com/firefly-iii/firefly-iii/issues/1733) You can configure Firefly III not to send emails with transaction information in them.
- [Issue 1040](https://github.com/firefly-iii/firefly-iii/issues/1040) Fixed various things that would not scale properly in the past.
- [Issue 1771](https://github.com/firefly-iii/firefly-iii/issues/1771) A link to the transaction that fits the bill.
- [Issue 1800](https://github.com/firefly-iii/firefly-iii/issues/1800) Icon updated to match others.
- MySQL database connection now forces the InnoDB to be used.
- [Issue 1583](https://github.com/firefly-iii/firefly-iii/issues/1583) Some times recurring transactions would not fire.
- [Issue 1607](https://github.com/firefly-iii/firefly-iii/issues/1607) Problems with the bunq API, finally solved?! (I feel like a clickbait YouTube video now)
- [Issue 1698](https://github.com/firefly-iii/firefly-iii/issues/1698) Certificate problems in the Docker container
- [Issue 1751](https://github.com/firefly-iii/firefly-iii/issues/1751) Bug in autocomplete
- [Issue 1760](https://github.com/firefly-iii/firefly-iii/issues/1760) Tag report bad math
- [Issue 1765](https://github.com/firefly-iii/firefly-iii/issues/1765) API inconsistencies for piggy banks.
- [Issue 1774](https://github.com/firefly-iii/firefly-iii/issues/1774) Integer exception in SQLite databases
- [Issue 1775](https://github.com/firefly-iii/firefly-iii/issues/1775) Heroku now supports all locales
- [Issue 1778](https://github.com/firefly-iii/firefly-iii/issues/1778) More autocomplete problems fixed
- [Issue 1747](https://github.com/firefly-iii/firefly-iii/issues/1747) Rules now stop at the right moment.
- [Issue 1781](https://github.com/firefly-iii/firefly-iii/issues/1781) Problems when creating new rules.
- [Issue 1784](https://github.com/firefly-iii/firefly-iii/issues/1784) Can now create a liability with an empty balance.
- [Issue 1785](https://github.com/firefly-iii/firefly-iii/issues/1785) Redirect error
- [Issue 1790](https://github.com/firefly-iii/firefly-iii/issues/1790) Show attachments for bills.
- [Issue 1792](https://github.com/firefly-iii/firefly-iii/issues/1792) Mention excluded accounts.
- [Issue 1798](https://github.com/firefly-iii/firefly-iii/issues/1798) Could not recreate deleted piggy banks
- [Issue 1805](https://github.com/firefly-iii/firefly-iii/issues/1805) Fixes when handling foreign currencies
- [Issue 1807](https://github.com/firefly-iii/firefly-iii/issues/1807) Also decrypt deleted records.
- [Issue 1812](https://github.com/firefly-iii/firefly-iii/issues/1812) Fix in transactions API
- [Issue 1815](https://github.com/firefly-iii/firefly-iii/issues/1815) Opening balance account name can now be translated.
- [Issue 1830](https://github.com/firefly-iii/firefly-iii/issues/1830) Multi-user in a single browser could leak autocomplete data.
# 4.7.7
- [Issue 954](https://github.com/firefly-iii/firefly-iii/issues/954) Some additional view chart ranges
- [Issue 1710](https://github.com/firefly-iii/firefly-iii/issues/1710) Added a new currency ([hamuz](https://github.com/hamuz))

View File

@@ -25,9 +25,9 @@ mkdir -p /var/storage/build
mkdir -p /var/storage/database
mkdir -p /var/storage/debugbar
mkdir -p /var/storage/export
mkdir -p /var/storage/framework/cache
mkdir -p /var/storage/framework/cache/v1
mkdir -p /var/storage/framework/sessions
mkdir -p /var/storage/framework/views
mkdir -p /var/storage/framework/views/v1
mkdir -p /var/storage/logs
mkdir -p /var/storage/upload
@@ -58,9 +58,5 @@ echo "Migrating..."
php /opt/app/artisan migrate --seed --force
echo "Done!"
echo "Clear cache.."
php /opt/app/artisan cache:clear
echo "Done"
# Start nginx.
/usr/sbin/nginx -c /opt/app/.sandstorm/service-config/nginx.conf -g "daemon off;"

File diff suppressed because it is too large Load Diff

View File

@@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
manifest = (
appTitle = (defaultText = "Firefly III"),
appVersion = 17,
appMarketingVersion = (defaultText = "4.7.7"),
appVersion = 21,
appMarketingVersion = (defaultText = "4.7.11"),
actions = [
# Define your "new document" handlers here.
@@ -103,7 +103,7 @@ const pkgdef :Spk.PackageDefinition = (
# not have been detected as a dependency during `spk dev`. If you list
# a directory here, its entire contents will be included recursively.
#bridgeConfig = (
bridgeConfig = (
# # Used for integrating permissions and roles into the Sandstorm shell
# # and for sandstorm-http-bridge to pass to your app.
# # Uncomment this block and adjust the permissions and roles to make
@@ -165,12 +165,12 @@ const pkgdef :Spk.PackageDefinition = (
# ),
# ],
# ),
# #apiPath = "/api",
apiPath = "/api/v1/",
# # Apps can export an API to the world. The API is to be used primarily by Javascript
# # code and native apps, so it can't serve out regular HTML to browsers. If a request
# # comes in to your app's API, sandstorm-http-bridge will prefix the request's path with
# # this string, if specified.
#),
),
);
const myCommand :Spk.Manifest.Command = (

View File

@@ -13,6 +13,7 @@ apt-get update
apt-get install -y python-software-properties software-properties-common
# install all languages
sed -i 's/# es_ES.UTF-8 UTF-8/es_ES.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# it_IT.UTF-8 UTF-8/it_IT.UTF-8 UTF-8/g' /etc/locale.gen
@@ -20,7 +21,7 @@ sed -i 's/# nl_NL.UTF-8 UTF-8/nl_NL.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# pl_PL.UTF-8 UTF-8/pl_PL.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# pt_BR.UTF-8 UTF-8/pt_BR.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# ru_RU.UTF-8 UTF-8/ru_RU.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# tr_TR.UTF-8 UTF-8/tr_TR.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# zh_TW.UTF-8 UTF-8/zh_TW.UTF-8 UTF-8/g' /etc/locale.gen
dpkg-reconfigure --frontend=noninteractive locales
@@ -38,7 +39,7 @@ echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sou
# install packages.
apt-get update
apt-get install -y nginx php7.2-fpm php7.2-mysql php7.2-gd php7.2-cli php7.2-curl git php7.2-dev php7.2-zip php7.2-intl php7.2-dom php7.2-mbstring php7.2-bcmath mysql-server
apt-get install -y nginx php7.2-fpm php7.2-mysql php7.2-gd php7.2-cli php7.2-curl php7.2-ldap git php7.2-dev php7.2-zip php7.2-intl php7.2-dom php7.2-mbstring php7.2-bcmath mysql-server
service nginx stop
service php7.2-fpm stop
service mysql stop

View File

@@ -1,29 +1,26 @@
language: php
php:
- 7.2
sudo: required
language: bash
env:
- VERSION=4.7.11
cache:
directories:
- vendor
- $HOME/.composer/cache
install:
- rm composer.lock
- composer update --no-scripts
- cp .env.testing .env
- php artisan clear-compiled
- php artisan 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:
- ./vendor/bin/phpunit -c phpunit.coverage.xml
after_success:
- travis_retry php vendor/bin/php-coveralls -x storage/build/clover-all.xml
dist: xenial
# safelist
branches:
only:
- develop
- master
services:
- docker
script:
# enable experimental features.
- echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
- sudo service docker restart
- docker version -f '{{.Server.Experimental}}'
- docker version
# build everything
- .deploy/docker/build-amd64.sh
- .deploy/docker/build-arm.sh
- .deploy/docker/manifest.sh

View File

@@ -1,111 +1,48 @@
FROM php:7.2-apache
# If building on a RPi, use --build-arg cores=3 to use all cores when compiling
# to speed up the image build
ARG CORES
ENV CORES ${CORES:-1}
ENV FIREFLY_PATH /var/www/firefly-iii/
ENV CURL_VERSION 7.60.0
ENV OPENSSL_VERSION 1.1.1-pre6
LABEL version="1.0" maintainer="thegrumpydictator@gmail.com"
# install packages
RUN apt-get update -y && \
apt-get install -y --no-install-recommends libcurl4-openssl-dev \
zlib1g-dev \
libjpeg62-turbo-dev \
wget \
libpng-dev \
libicu-dev \
libedit-dev \
libtidy-dev \
libxml2-dev \
unzip \
libsqlite3-dev \
nano \
libpq-dev \
libbz2-dev \
gettext-base \
cron \
rsyslog \
supervisor \
locales && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install latest curl
RUN cd /tmp && \
wget https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz && \
tar -xvf openssl-${OPENSSL_VERSION}.tar.gz && \
cd openssl-${OPENSSL_VERSION} && \
./config && \
make -j${CORES} && \
make install
RUN cd /tmp && \
wget https://curl.haxx.se/download/curl-${CURL_VERSION}.tar.gz && \
tar -xvf curl-${CURL_VERSION}.tar.gz && \
cd curl-${CURL_VERSION} && \
./configure --with-ssl --host=$(gcc -dumpmachine) && \
make -j${CORES} && \
make install
# Make sure that libcurl is using the newer curl libaries
RUN echo "/usr/local/lib" >> /etc/ld.so.conf.d/00-curl.conf && ldconfig
# Mimic the Debian/Ubuntu config file structure for supervisor
COPY .deploy/docker/supervisord.conf /etc/supervisor/supervisord.conf
RUN mkdir -p /etc/supervisor/conf.d /var/log/supervisor
# copy Firefly III supervisor conf file.
COPY ./.deploy/docker/firefly-iii.conf /etc/supervisor/conf.d/firefly-iii.conf
# copy cron job supervisor conf file.
COPY ./.deploy/docker/cronjob.conf /etc/supervisor/conf.d/cronjob.conf
# test crons added via crontab
RUN echo "0 3 * * * /usr/local/bin/php /var/www/firefly-iii/artisan firefly:cron" | crontab -
#RUN (crontab -l ; echo "*/1 * * * * free >> /var/www/firefly-iii/public/cron.html") 2>&1 | crontab -
# Install PHP exentions.
RUN docker-php-ext-install -j$(nproc) gd intl tidy zip bcmath pdo_mysql bz2 pdo_pgsql
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Generate locales supported by Firefly III
RUN echo "en_US.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
# Enable apache mod rewrite..
RUN a2enmod rewrite
# Enable apache mod ssl..
RUN a2enmod ssl
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
LABEL version="1.3" maintainer="thegrumpydictator@gmail.com"
# Create volumes
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
# Enable default site (Firefly III)
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
# Install some stuff
RUN apt-get update && apt-get install -y libpng-dev \
libicu-dev \
unzip \
gettext-base \
libldap2-dev \
libpq-dev \
locales \
libmemcached-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Make sure we own Firefly III directory
RUN chown -R www-data:www-data /var/www && chmod -R 775 $FIREFLY_PATH/storage
# Copy in Firefly Source
# Copy in Firefly III source
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
# Fix the link to curl:
RUN rm -rf /usr/local/lib/libcurl.so.4 && ln -s /usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/local/lib/libcurl.so.4
# copy ca certs to correct location
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
# Run composer
ENV COMPOSER_ALLOW_SUPERUSER 1
RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
# Enable default site (Firefly III)
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
# Run a lot of installation commands:
RUN chown -R www-data:www-data /var/www && \
chmod -R 775 $FIREFLY_PATH/storage && \
a2enmod rewrite && a2enmod ssl && \
docker-php-ext-configure ldap --with-libdir=lib/$(gcc -dumpmachine)/ && \
docker-php-ext-install -j$(nproc) zip bcmath ldap gd pdo_pgsql pdo_mysql intl opcache && \
pecl install memcached-3.1.3 && \
docker-php-ext-enable memcached && \
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\nzh_TW.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\n\n" > /etc/locale.gen && \
locale-gen && \
composer install --prefer-dist --no-dev --no-scripts --no-suggest
# Expose port 80
EXPOSE 80

51
Dockerfile.amd64 Normal file
View File

@@ -0,0 +1,51 @@
FROM php:7.2-apache
ARG ARCH
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
LABEL version="1.3" maintainer="thegrumpydictator@gmail.com"
# Create volumes
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
# Install some stuff
RUN apt-get update && apt-get install -y libpng-dev \
libicu-dev \
unzip \
gettext-base \
libldap2-dev \
libpq-dev \
locales \
libmemcached-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Copy in Firefly III source
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
# copy ca certs to correct location
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
# Enable default site (Firefly III)
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
# Run a lot of installation commands:
RUN chown -R www-data:www-data /var/www && \
chmod -R 775 $FIREFLY_PATH/storage && \
a2enmod rewrite && a2enmod ssl && \
docker-php-ext-configure ldap --with-libdir=lib/$(gcc -dumpmachine)/ && \
docker-php-ext-install -j$(nproc) zip bcmath ldap gd pdo_pgsql pdo_mysql intl opcache && \
pecl install memcached-3.1.3 && \
docker-php-ext-enable memcached && \
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\nzh_TW.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\n\n" > /etc/locale.gen && \
locale-gen && \
composer install --prefer-dist --no-dev --no-scripts --no-suggest
# Expose port 80
EXPOSE 80
# Run entrypoint thing
ENTRYPOINT [".deploy/docker/entrypoint.sh"]

50
Dockerfile.arm Normal file
View File

@@ -0,0 +1,50 @@
FROM arm32v7/php:7.2.8-apache-stretch
ARG ARCH
COPY tmp/qemu-arm-static /usr/bin/qemu-arm-static
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
LABEL version="1.3" maintainer="thegrumpydictator@gmail.com"
# Create volumes
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
# Install some stuff
RUN apt-get update && apt-get install -y libpng-dev \
libicu-dev \
unzip \
gettext-base \
libldap2-dev \
libpq-dev \
locales \
libmemcached-dev
# Copy in Firefly III source
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
# copy ca certs to correct location
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
# Enable default site (Firefly III)
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
# Run a lot of installation commands:
RUN chown -R www-data:www-data /var/www && \
chmod -R 775 $FIREFLY_PATH/storage && \
a2enmod rewrite && a2enmod ssl && \
docker-php-ext-configure ldap --with-libdir=lib/$(gcc -dumpmachine)/ && \
docker-php-ext-install -j$(nproc) zip bcmath ldap gd pdo_pgsql pdo_mysql intl opcache && \
pecl install memcached-3.1.3 && \
docker-php-ext-enable memcached && \
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\nzh_TW.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\n\n" > /etc/locale.gen && \
locale-gen && \
composer install --prefer-dist --no-dev --no-scripts --no-suggest
# Expose port 80
EXPOSE 80
# Run entrypoint thing
ENTRYPOINT [".deploy/docker/entrypoint.sh"]

50
Dockerfile.arm64 Normal file
View File

@@ -0,0 +1,50 @@
FROM arm32v7/php:7.2.8-apache-stretch
ARG ARCH
COPY tmp/qemu-arm-static /usr/bin/qemu-arm-static
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
LABEL version="1.3" maintainer="thegrumpydictator@gmail.com"
# Create volumes
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
# Install some stuff
RUN apt-get update && apt-get install -y libpng-dev \
libicu-dev \
unzip \
gettext-base \
libldap2-dev \
libpq-dev \
locales \
libmemcached-dev
# Copy in Firefly III source
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
# copy ca certs to correct location
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
# Enable default site (Firefly III)
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
# Run a lot of installation commands:
RUN chown -R www-data:www-data /var/www && \
chmod -R 775 $FIREFLY_PATH/storage && \
a2enmod rewrite && a2enmod ssl && \
docker-php-ext-configure ldap --with-libdir=lib/$(gcc -dumpmachine)/ && \
docker-php-ext-install -j$(nproc) zip bcmath ldap gd pdo_pgsql pdo_mysql intl opcache && \
pecl install memcached-3.1.3 && \
docker-php-ext-enable memcached && \
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\nzh_TW.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\n\n" > /etc/locale.gen && \
locale-gen && \
composer install --prefer-dist --no-dev --no-scripts --no-suggest
# Expose port 80
EXPOSE 80
# Run entrypoint thing
ENTRYPOINT [".deploy/docker/entrypoint.sh"]

View File

@@ -51,6 +51,9 @@
"buildpacks": [
{
"url": "heroku/php"
},
{
"url": "https://github.com/heroku/heroku-buildpack-locale"
}
],
"env": {

View File

@@ -75,7 +75,12 @@ class AboutController extends Controller
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item(auth()->user(), new UserTransformer($this->parameters), 'users');
/** @var UserTransformer $transformer */
$transformer = app(UserTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item(auth()->user(), $transformer, 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}

View File

@@ -24,15 +24,21 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\AccountRequest;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
@@ -46,8 +52,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class AccountController extends Controller
{
/** @var CurrencyRepositoryInterface The currency repository */
private $currencyRepository;
use AccountFilter, TransactionFilter;
/** @var AccountRepositoryInterface The account repository */
private $repository;
@@ -65,9 +70,6 @@ class AccountController extends Controller
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser($user);
return $next($request);
}
);
@@ -105,7 +107,7 @@ class AccountController extends Controller
$this->parameters->set('type', $type);
// types to get, page size:
$types = $this->mapTypes($this->parameters->get('type'));
$types = $this->mapAccountTypes($this->parameters->get('type'));
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
@@ -119,12 +121,58 @@ class AccountController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($accounts, new AccountTransformer($this->parameters), 'accounts');
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($accounts, $transformer, 'accounts');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all of them.
*
* @param Request $request
* @param Account $account
*
* @return JsonResponse]
*/
public function piggyBanks(Request $request, Account $account): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->getPiggyBanks($account);
$count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.accounts.piggy_banks', [$account->id]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show single instance.
*
@@ -136,14 +184,13 @@ class AccountController extends Controller
public function show(Request $request, Account $account): JsonResponse
{
$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');
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($account, $transformer, 'accounts');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -157,18 +204,80 @@ class AccountController extends Controller
*/
public function store(AccountRequest $request): JsonResponse
{
$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'] = null === $currency ? 0 : $currency->id;
}
$data = $request->getAll();
$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');
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($account, $transformer, 'accounts');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show all transactions.
*
* @param Request $request
* @param Account $account
*
* @return JsonResponse
*/
public function transactions(Request $request, Account $account): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
// user can overrule page size with limit parameter.
$limit = $this->parameters->get('limit');
if (null !== $limit && $limit > 0) {
$pageSize = $limit;
}
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
if ($this->repository->isAsset($account)) {
$collector->setAccounts(new Collection([$account]));
}
if (!$this->repository->isAsset($account)) {
$collector->setOpposingAccounts(new Collection([$account]));
}
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.accounts.transactions', [$account->id]) . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -183,68 +292,18 @@ class AccountController extends Controller
*/
public function update(AccountRequest $request, Account $account): JsonResponse
{
$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'] = null === $currency ? 0 : $currency->id;
}
// set correct type:
$data = $request->getAll();
$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');
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($account, $transformer, 'accounts');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* All the available types.
*
* @param string $type
*
* @return array
*/
private function mapTypes(string $type): array
{
$types = [
'all' => [AccountType::DEFAULT, AccountType::CASH, AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE,
AccountType::INITIAL_BALANCE, AccountType::BENEFICIARY, AccountType::IMPORT, AccountType::RECONCILIATION,
AccountType::LOAN,AccountType::DEBT, AccountType::MORTGAGE],
'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,],
'hidden' => [AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION],
'liability' => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD],
'liabilities' => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD],
'cc' => [AccountType::CREDITCARD],
'creditcard' => [AccountType::CREDITCARD],
'credit_card' => [AccountType::CREDITCARD],
AccountType::DEFAULT => [AccountType::DEFAULT],
AccountType::CASH => [AccountType::CASH],
AccountType::ASSET => [AccountType::ASSET],
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],
AccountType::MORTGAGE => [AccountType::MORTGAGE],
AccountType::DEBT => [AccountType::DEBT],
AccountType::CREDITCARD => [AccountType::CREDITCARD],
];
$return = $types['all'];
if (isset($types[$type])) {
$return = $types[$type];
}
return $return; // @codeCoverageIgnore
}
}

View File

@@ -144,7 +144,12 @@ class AttachmentController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($attachments, new AttachmentTransformer($this->parameters), 'attachments');
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -161,14 +166,14 @@ class AttachmentController extends Controller
public function show(Request $request, Attachment $attachment): JsonResponse
{
$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($attachment, new AttachmentTransformer($this->parameters), 'attachments');
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($attachment, $transformer, 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -188,7 +193,12 @@ class AttachmentController extends Controller
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($attachment, new AttachmentTransformer($this->parameters), 'attachments');
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($attachment, $transformer, 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -209,7 +219,11 @@ class AttachmentController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($attachment, new AttachmentTransformer($this->parameters), 'attachments');
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($attachment, $transformer, 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}

View File

@@ -25,7 +25,9 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\AvailableBudgetRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\AvailableBudgetTransformer;
@@ -102,6 +104,17 @@ class AvailableBudgetController extends Controller
// get list of available budgets. Count it and split it.
$collection = $this->repository->getAvailableBudgets();
// filter list on start and end date, if present.
// TODO: put this in the query.
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');
if(null !== $start && null !== $end) {
$collection = $collection->filter(function(AvailableBudget $availableBudget) use ($start, $end) {
return $availableBudget->start_date->gte($start) && $availableBudget->end_date->lte($end);
});
}
$count = $collection->count();
$availableBudgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
@@ -111,7 +124,12 @@ class AvailableBudgetController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($availableBudgets, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
/** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($availableBudgets, $transformer, 'available_budgets');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -127,16 +145,15 @@ class AvailableBudgetController extends Controller
*/
public function show(Request $request, AvailableBudget $availableBudget): JsonResponse
{
$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($availableBudget, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
/** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($availableBudget, $transformer, 'available_budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -151,26 +168,29 @@ class AvailableBudgetController extends Controller
*/
public function store(AvailableBudgetRequest $request): JsonResponse
{
$data = $request->getAll();
$currency = $this->currencyRepository->findNull($data['currency_id']);
$data = $request->getAll();
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find($data['currency_id'], $data['currency_code']);
if (null === $currency) {
$currency = $this->currencyRepository->findByCodeNull($data['currency_code']);
$currency = app('amount')->getDefaultCurrency();
}
if (null === $currency) {
throw new FireflyException('Could not find the indicated currency.');
}
$availableBudget = $this->repository->setAvailableBudget($currency, $data['start_date'], $data['end_date'], $data['amount']);
$availableBudget = $this->repository->setAvailableBudget($currency, $data['start'], $data['end'], $data['amount']);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($availableBudget, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
/** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($availableBudget, $transformer, 'available_budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the specified resource in storage.
*
@@ -182,12 +202,32 @@ class AvailableBudgetController extends Controller
public function update(AvailableBudgetRequest $request, AvailableBudget $availableBudget): JsonResponse
{
$data = $request->getAll();
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
/** @var TransactionCurrency $currency */
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
if (null === $currency) {
// use default currency:
$currency = app('amount')->getDefaultCurrency();
}
$currency->enabled = true;
$currency->save();
unset($data['currency_code']);
$data['currency_id'] = $currency->id;
$this->repository->updateAvailableBudget($availableBudget, $data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($availableBudget, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
/** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($availableBudget, $transformer, 'available_budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -26,12 +26,18 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\BillRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\BillTransformer;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
@@ -44,6 +50,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class BillController extends Controller
{
use TransactionFilter;
/** @var BillRepositoryInterface The bill repository */
private $repository;
@@ -67,6 +74,43 @@ class BillController extends Controller
);
}
/**
* Display a listing of the resource.
*
* @param Request $request
* @param Bill $bill
*
* @return JsonResponse
*/
public function attachments(Request $request, Bill $bill): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$collection = $this->repository->getAttachments($bill);
$count = $collection->count();
$attachments = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($attachments, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.bills.attachments', [$bill->id]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Remove the specified resource from storage.
*
@@ -99,12 +143,56 @@ class BillController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($bills, new BillTransformer($this->parameters), 'bills');
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($bills, $transformer, 'bills');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all of them.
*
* @param Request $request
* @param Bill $bill
*
* @return JsonResponse
*/
public function rules(Request $request, Bill $bill): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->getRulesForBill($bill);
$count = $collection->count();
$rules = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.bills.rules', [$bill->id]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($rules, $transformer, 'rules');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show the specified bill.
@@ -117,14 +205,14 @@ class BillController extends Controller
public function show(Request $request, Bill $bill): JsonResponse
{
$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');
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($bill, $transformer, 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -145,7 +233,11 @@ class BillController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($bill, $transformer, 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -153,6 +245,53 @@ class BillController extends Controller
}
/**
* Show all transactions.
*
* @param Request $request
*
* @param Bill $bill
*
* @return JsonResponse
*/
public function transactions(Request $request, Bill $bill): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setBills(new Collection([$bill]));
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.bills.transactions', [$bill->id]) . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update a bill.
@@ -170,7 +309,11 @@ class BillController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($bill, new BillTransformer($this->parameters), 'bills');
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($bill, $transformer, 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -23,11 +23,16 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\BudgetLimitRequest;
use FireflyIII\Api\V1\Requests\BudgetRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\Transformers\BudgetTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -45,6 +50,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class BudgetController extends Controller
{
use TransactionFilter;
/** @var BudgetRepositoryInterface The budget repository */
private $repository;
@@ -68,6 +74,39 @@ class BudgetController extends Controller
);
}
/**
* Display a listing of the resource.
*
* @param Request $request
* @param Budget $budget
*
* @return JsonResponse
*/
public function budgetLimits(Request $request, Budget $budget): JsonResponse
{
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$this->parameters->set('budget_id', $budget->id);
$collection = $this->repository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end'));
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.budgets.budget_limits', [$budget->id]) . $this->buildParams());
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($budgetLimits, $transformer, 'budget_limits');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Remove the specified resource from storage.
*
@@ -109,13 +148,17 @@ class BudgetController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($budgets, new BudgetTransformer($this->parameters), 'budgets');
/** @var BudgetTransformer $transformer */
$transformer = app(BudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($budgets, $transformer, 'budgets');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show a budget.
*
@@ -127,14 +170,14 @@ class BudgetController extends Controller
public function show(Request $request, Budget $budget): JsonResponse
{
$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($budget, new BudgetTransformer($this->parameters), 'budgets');
/** @var BudgetTransformer $transformer */
$transformer = app(BudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budget, $transformer, 'budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -155,13 +198,99 @@ class BudgetController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets');
/** @var BudgetTransformer $transformer */
$transformer = app(BudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budget, $transformer, 'budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new budget.'); // @codeCoverageIgnore
}
/**
* Store a newly created resource in storage.
*
* @param BudgetLimitRequest $request
* @param Budget $budget
*
* @return JsonResponse
*/
public function storeBudgetLimit(BudgetLimitRequest $request, Budget $budget): JsonResponse
{
$data = $request->getAll();
$data['budget'] = $budget;
$budgetLimit = $this->repository->storeBudgetLimit($data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show all transactions.
*
* @param Request $request
*
* @param Budget $budget
*
* @return JsonResponse
*/
public function transactions(Request $request, Budget $budget): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// user can overrule page size with limit parameter.
$limit = $this->parameters->get('limit');
if (null !== $limit && $limit > 0) {
$pageSize = $limit;
}
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setBudget($budget);
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.budgets.transactions', [$budget->id]) . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update a budget.
@@ -179,7 +308,11 @@ class BudgetController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets');
/** @var BudgetTransformer $transformer */
$transformer = app(BudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budget, $transformer, 'budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -26,9 +26,12 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\BudgetLimitRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -48,6 +51,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class BudgetLimitController extends Controller
{
use TransactionFilter;
/** @var BudgetRepositoryInterface The budget repository */
private $repository;
@@ -113,7 +117,12 @@ class BudgetLimitController extends Controller
$paginator->setPath(route('api.v1.budget_limits.index') . $this->buildParams());
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($budgetLimits, new BudgetLimitTransformer($this->parameters), 'budget_limits');
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($budgetLimits, $transformer, 'budget_limits');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -130,14 +139,14 @@ class BudgetLimitController extends Controller
public function show(Request $request, BudgetLimit $budgetLimit): JsonResponse
{
$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($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits');
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -163,7 +172,55 @@ class BudgetLimitController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits');
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show all transactions.
*
* @param Request $request
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
public function transactions(Request $request, BudgetLimit $budgetLimit): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setBudget($budgetLimit->budget);
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date);
$collector->setLimit($pageSize)->setPage($this->parameters->get('page'));
$collector->setTypes($types);
$paginator = $collector->getPaginatedTransactions();
$paginator->setPath(route('api.v1.budget_limits.transactions', [$budgetLimit->id]) . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -178,18 +235,18 @@ class BudgetLimitController extends Controller
*/
public function update(BudgetLimitRequest $request, BudgetLimit $budgetLimit): JsonResponse
{
$data = $request->getAll();
$budget = $this->repository->findNull($data['budget_id']);
if (null === $budget) {
$budget = $budgetLimit->budget;
}
$data['budget'] = $budget;
$data = $request->getAll();
$data['budget'] = $budgetLimit->budget;
$budgetLimit = $this->repository->updateBudgetLimit($budgetLimit, $data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits');
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -25,9 +25,14 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\CategoryRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CategoryTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -45,6 +50,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class CategoryController extends Controller
{
use TransactionFilter;
/** @var CategoryRepositoryInterface The category repository */
private $repository;
@@ -109,7 +115,13 @@ class CategoryController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($categories, new CategoryTransformer($this->parameters), 'categories');
/** @var CategoryTransformer $transformer */
$transformer = app(CategoryTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($categories, $transformer, 'categories');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -127,14 +139,14 @@ class CategoryController extends Controller
public function show(Request $request, Category $category): JsonResponse
{
$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($category, new CategoryTransformer($this->parameters), 'categories');
/** @var CategoryTransformer $transformer */
$transformer = app(CategoryTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($category, $transformer, 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -155,13 +167,68 @@ class CategoryController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new CategoryTransformer($this->parameters), 'categories');
/** @var CategoryTransformer $transformer */
$transformer = app(CategoryTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($category, $transformer, 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new category.'); // @codeCoverageIgnore
}
/**
* Show all transactions.
*
* @param Request $request
*
* @param Category $category
*
* @return JsonResponse
*/
public function transactions(Request $request, Category $category): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setCategory($category);
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.categories.transactions', [$category->id]) . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the category.
@@ -179,7 +246,11 @@ class CategoryController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new CategoryTransformer($this->parameters), 'categories');
/** @var CategoryTransformer $transformer */
$transformer = app(CategoryTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($category, $transformer, 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -0,0 +1,348 @@
<?php
/**
* AccountController.php
* Copyright (c) 2019 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\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
/**
* Class AccountController
*/
class AccountController extends Controller
{
/** @var CurrencyRepositoryInterface */
private $currencyRepository;
/** @var AccountRepositoryInterface */
private $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser($user);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function expenseOverview(Request $request): JsonResponse
{
// parameters for chart:
$start = (string)$request->get('start');
$end = (string)$request->get('end');
if ('' === $start || '' === $end) {
throw new FireflyException('Start and end are mandatory parameters.');
}
$start = Carbon::createFromFormat('Y-m-d', $start);
$end = Carbon::createFromFormat('Y-m-d', $end);
$start->subDay();
// prep some vars:
$currencies = [];
$chartData = [];
$tempData = [];
// grab all accounts and names
$accounts = $this->repository->getAccountsByType([AccountType::EXPENSE]);
$accountNames = $this->extractNames($accounts);
$startBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $start);
$endBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $end);
// loop the end balances. This is an array for each account ($expenses)
foreach ($endBalances as $accountId => $expenses) {
$accountId = (int)$accountId;
// loop each expense entry (each entry can be a different currency).
foreach ($expenses as $currencyId => $endAmount) {
$currencyId = (int)$currencyId;
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startAmount = $startBalances[$accountId][$currencyId] ?? '0';
$diff = bcsub($endAmount, $startAmount);
$currencies[$currencyId] = $currencies[$currencyId] ?? $this->currencyRepository->findNull($currencyId);
if (0 !== bccomp($diff, '0')) {
// store the values in a temporary array.
$tempData[] = [
'name' => $accountNames[$accountId],
'difference' => $diff,
'diff_float' => (float)$diff,
'currency_id' => $currencyId,
];
}
}
}
// sort temp array by amount.
$amounts = array_column($tempData, 'diff_float');
array_multisort($amounts, SORT_DESC, $tempData);
// loop all found currencies and build the data array for the chart.
/**
* @var int $currencyId
* @var TransactionCurrency $currency
*/
foreach ($currencies as $currencyId => $currency) {
$currentSet = [
'label' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'type' => 'bar', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => $this->expandNames($tempData),
];
$chartData[$currencyId] = $currentSet;
}
// loop temp data and place data in correct array:
foreach ($tempData as $entry) {
$currencyId = $entry['currency_id'];
$name = $entry['name'];
$chartData[$currencyId]['entries'][$name] = round($entry['difference'], $chartData[$currencyId]['currency_decimal_places']);
}
$chartData = array_values($chartData);
return response()->json($chartData);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function revenueOverview(Request $request): JsonResponse
{
// parameters for chart:
$start = (string)$request->get('start');
$end = (string)$request->get('end');
if ('' === $start || '' === $end) {
throw new FireflyException('Start and end are mandatory parameters.');
}
$start = Carbon::createFromFormat('Y-m-d', $start);
$end = Carbon::createFromFormat('Y-m-d', $end);
$start->subDay();
// prep some vars:
$currencies = [];
$chartData = [];
$tempData = [];
// grab all accounts and names
$accounts = $this->repository->getAccountsByType([AccountType::REVENUE]);
$accountNames = $this->extractNames($accounts);
$startBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $start);
$endBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $end);
// loop the end balances. This is an array for each account ($expenses)
foreach ($endBalances as $accountId => $expenses) {
$accountId = (int)$accountId;
// loop each expense entry (each entry can be a different currency).
foreach ($expenses as $currencyId => $endAmount) {
$currencyId = (int)$currencyId;
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startAmount = $startBalances[$accountId][$currencyId] ?? '0';
$diff = bcsub($endAmount, $startAmount);
$currencies[$currencyId] = $currencies[$currencyId] ?? $this->currencyRepository->findNull($currencyId);
if (0 !== bccomp($diff, '0')) {
// store the values in a temporary array.
$tempData[] = [
'name' => $accountNames[$accountId],
'difference' => bcmul($diff,'-1'),
'diff_float' => (float)$diff * -1,
'currency_id' => $currencyId,
];
}
}
}
// sort temp array by amount.
$amounts = array_column($tempData, 'diff_float');
array_multisort($amounts, SORT_DESC, $tempData);
// loop all found currencies and build the data array for the chart.
/**
* @var int $currencyId
* @var TransactionCurrency $currency
*/
foreach ($currencies as $currencyId => $currency) {
$currentSet = [
'label' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'type' => 'bar', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => $this->expandNames($tempData),
];
$chartData[$currencyId] = $currentSet;
}
// loop temp data and place data in correct array:
foreach ($tempData as $entry) {
$currencyId = $entry['currency_id'];
$name = $entry['name'];
$chartData[$currencyId]['entries'][$name] = round($entry['difference'], $chartData[$currencyId]['currency_decimal_places']);
}
$chartData = array_values($chartData);
return response()->json($chartData);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function overview(Request $request): JsonResponse
{
// parameters for chart:
$start = (string)$request->get('start');
$end = (string)$request->get('end');
if ('' === $start || '' === $end) {
throw new FireflyException('Start and end are mandatory parameters.');
}
$start = Carbon::createFromFormat('Y-m-d', $start);
$end = Carbon::createFromFormat('Y-m-d', $end);
// user's preferences
$defaultSet = $this->repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray();
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
$default = app('amount')->getDefaultCurrency();
if (0 === \count($frontPage->data)) {
$frontPage->data = $defaultSet;
$frontPage->save();
}
// get accounts:
$accounts = $this->repository->getAccountsById($frontPage->data);
$chartData = [];
/** @var Account $account */
foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $default;
}
$currentSet = [
'label' => $account->name,
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'type' => 'line', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
];
$currentStart = clone $start;
$range = app('steam')->balanceInRange($account, $start, clone $end);
$previous = round(array_values($range)[0], 12);
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->format('Y-m-d');
$balance = isset($range[$format]) ? round($range[$format], 12) : $previous;
$previous = $balance;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;
}
$chartData[] = $currentSet;
}
return response()->json($chartData);
}
/**
* Small helper function for the revenue and expense account charts.
* TODO should include Trait instead of doing this.
*
* @param array $names
*
* @return array
*/
protected function expandNames(array $names): array
{
$result = [];
foreach ($names as $entry) {
$result[$entry['name']] = 0;
}
return $result;
}
/**
* Small helper function for the revenue and expense account charts.
* TODO should include Trait instead of doing this.
*
* @param Collection $accounts
*
* @return array
*/
protected function extractNames(Collection $accounts): array
{
$return = [];
/** @var Account $account */
foreach ($accounts as $account) {
$return[$account->id] = $account->name;
}
return $return;
}
}

View File

@@ -0,0 +1,114 @@
<?php
/**
* AvailableBudgetController.php
* Copyright (c) 2019 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\Api\V1\Controllers\Chart;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
/**
* Class AvailableBudgetController
*/
class AvailableBudgetController extends Controller
{
/** @var BudgetRepositoryInterface */
private $repository;
/**
* AvailableBudgetController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(BudgetRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @param AvailableBudget $availableBudget
*
* @return JsonResponse
*/
public function overview(Request $request, AvailableBudget $availableBudget): JsonResponse
{
$currency = $availableBudget->transactionCurrency;
$budgets = $this->repository->getActiveBudgets();
$budgetInformation = $this->repository->spentInPeriodMc($budgets, new Collection, $availableBudget->start_date, $availableBudget->end_date);
$spent = 0.0;
// get for current currency
foreach ($budgetInformation as $spentInfo) {
if ($spentInfo['currency_id'] === $availableBudget->transaction_currency_id) {
$spent = $spentInfo['amount'];
}
}
$left = bcadd($availableBudget->amount, (string)$spent);
// left less than zero? Set to zero.
if (bccomp($left, '0') === -1) {
$left = '0';
}
$chartData = [
[
'label' => trans('firefly.spent'),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'type' => 'pie',
'yAxisID' => 0, // 0, 1, 2
'entries' => [$spent * -1],
],
[
'label' => trans('firefly.left'),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'type' => 'line', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [round($left, $currency->decimal_places)],
],
];
return response()->json($chartData);
}
}

View File

@@ -0,0 +1,209 @@
<?php
/**
* CategoryController.php
* Copyright (c) 2019 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\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
/**
* Class CategoryController
*/
class CategoryController extends Controller
{
/** @var CategoryRepositoryInterface */
private $categoryRepository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->categoryRepository = app(CategoryRepositoryInterface::class);
$this->categoryRepository->setUser($user);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function overview(Request $request): JsonResponse
{
// parameters for chart:
$start = (string)$request->get('start');
$end = (string)$request->get('end');
if ('' === $start || '' === $end) {
throw new FireflyException('Start and end are mandatory parameters.');
}
$start = Carbon::createFromFormat('Y-m-d', $start);
$end = Carbon::createFromFormat('Y-m-d', $end);
$tempData = [];
$spent = $this->categoryRepository->spentInPeriodPerCurrency(new Collection, new Collection, $start, $end);
$earned = $this->categoryRepository->earnedInPeriodPerCurrency(new Collection, new Collection, $start, $end);
$categories = [];
// earned:
foreach ($earned as $categoryId => $row) {
$categoryName = $row['name'];
foreach ($row['earned'] as $currencyId => $income) {
// find or make set for currency:
$key = sprintf('%s-e', $currencyId);
$decimalPlaces = $income['currency_decimal_places'];
if (!isset($tempData[$key])) {
$tempData[$key] = [
'label' => (string)trans('firefly.box_earned_in_currency', ['currency' => $income['currency_symbol']]),
'currency_id' => $income['currency_id'],
'currency_code' => $income['currency_code'],
'currency_symbol' => $income['currency_symbol'],
'currency_decimal_places' => $decimalPlaces,
'type' => 'bar', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
];
}
$amount = round($income['earned'], $decimalPlaces);
$categories[$categoryName] = isset($categories[$categoryName]) ? $categories[$categoryName] + $amount : $amount;
$tempData[$key]['entries'][$categoryName]
= $amount;
}
}
// earned with no category:
$noCategory = $this->categoryRepository->earnedInPeriodPcWoCategory(new Collection, $start, $end);
foreach ($noCategory as $currencyId => $income) {
$categoryName = (string)trans('firefly.no_category');
// find or make set for currency:
$key = sprintf('%s-e', $currencyId);
$decimalPlaces = $income['currency_decimal_places'];
if (!isset($tempData[$key])) {
$tempData[$key] = [
'label' => (string)trans('firefly.box_earned_in_currency', ['currency' => $income['currency_symbol']]),
'currency_id' => $income['currency_id'],
'currency_code' => $income['currency_code'],
'currency_symbol' => $income['currency_symbol'],
'currency_decimal_places' => $decimalPlaces,
'type' => 'bar', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
];
}
$amount = round($income['spent'], $decimalPlaces);
$categories[$categoryName] = isset($categories[$categoryName]) ? $categories[$categoryName] + $amount : $amount;
$tempData[$key]['entries'][$categoryName]
= $amount;
}
// spent
foreach ($spent as $categoryId => $row) {
$categoryName = $row['name'];
// create a new set if necessary, "spent (EUR)":
foreach ($row['spent'] as $currencyId => $expense) {
// find or make set for currency:
$key = sprintf('%s-s', $currencyId);
$decimalPlaces = $expense['currency_decimal_places'];
if (!isset($tempData[$key])) {
$tempData[$key] = [
'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $expense['currency_symbol']]),
'currency_id' => $expense['currency_id'],
'currency_code' => $expense['currency_code'],
'currency_symbol' => $expense['currency_symbol'],
'currency_decimal_places' => $decimalPlaces,
'type' => 'bar', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
];
}
$amount = round($expense['spent'], $decimalPlaces);
$categories[$categoryName] = isset($categories[$categoryName]) ? $categories[$categoryName] + $amount : $amount;
$tempData[$key]['entries'][$categoryName]
= $amount;
}
}
// spent with no category
$noCategory = $this->categoryRepository->spentInPeriodPcWoCategory(new Collection, $start, $end);
foreach ($noCategory as $currencyId => $expense) {
$categoryName = (string)trans('firefly.no_category');
// find or make set for currency:
$key = sprintf('%s-s', $currencyId);
$decimalPlaces = $expense['currency_decimal_places'];
if (!isset($tempData[$key])) {
$tempData[$key] = [
'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $expense['currency_symbol']]),
'currency_id' => $expense['currency_id'],
'currency_code' => $expense['currency_code'],
'currency_symbol' => $expense['currency_symbol'],
'currency_decimal_places' => $decimalPlaces,
'type' => 'bar', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
];
}
$amount = round($expense['spent'], $decimalPlaces);
$categories[$categoryName] = isset($categories[$categoryName]) ? $categories[$categoryName] + $amount : $amount;
$tempData[$key]['entries'][$categoryName]
= $amount;
}
asort($categories);
$keys = array_keys($categories);
// re-sort every spent array and add 0 for missing entries.
foreach ($tempData as $index => $set) {
$oldSet = $set['entries'];
$newSet = [];
foreach ($keys as $key) {
$value = $oldSet[$key] ?? 0;
$value = $value < 0 ? $value * -1 : $value;
$newSet[$key] = $value;
}
$tempData[$index]['entries'] = $newSet;
}
$chartData = array_values($tempData);
return response()->json($chartData);
}
}

View File

@@ -23,12 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\ConfigurationRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Configuration;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* Class ConfigurationController.
@@ -78,31 +78,17 @@ class ConfigurationController extends Controller
/**
* Update the configuration.
*
* @param Request $request
* @param ConfigurationRequest $request
* @param string $name
*
* @return JsonResponse
* @throws FireflyException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function update(Request $request): JsonResponse
public function update(ConfigurationRequest $request, string $name): JsonResponse
{
$name = $request->get('name');
$value = $request->get('value');
$valid = ['is_demo_site', 'permission_update_check', 'single_user_mode'];
if (!\in_array($name, $valid, true)) {
throw new FireflyException('You cannot edit this configuration value.');
}
$configValue = '';
switch ($name) {
case 'is_demo_site':
case 'single_user_mode':
$configValue = 'true' === $value;
break;
case 'permission_update_check':
$configValue = (int)$value >= -1 && (int)$value <= 1 ? (int)$value : -1;
break;
}
app('fireflyconfig')->set($name, $configValue);
$data = $request->getAll();
app('fireflyconfig')->set($name, $data['value']);
$configData = $this->getConfigData();
return response()->json(['data' => $configData], 200)->header('Content-Type', 'application/vnd.api+json');

View File

@@ -100,11 +100,11 @@ class Controller extends BaseController
// some date fields:
$dates = ['start', 'end', 'date'];
foreach ($dates as $field) {
$date = request()->get($field);
$date = request()->query->get($field);
$obj = null;
if (null !== $date) {
try {
$obj = new Carbon($date);
$obj = Carbon::parse($date);
} catch (InvalidDateException $e) {
// don't care
Log::error(sprintf('Invalid date exception in API controller: %s', $e->getMessage()));
@@ -113,6 +113,15 @@ class Controller extends BaseController
$bag->set($field, $obj);
}
// integer fields:
$integers = ['limit'];
foreach ($integers as $integer) {
$value = request()->query->get($integer);
if (null !== $value) {
$bag->set($integer, (int)$value);
}
}
return $bag;
}

View File

@@ -26,14 +26,41 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\CurrencyRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Account;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\AvailableBudgetTransformer;
use FireflyIII\Transformers\BillTransformer;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\Transformers\CurrencyExchangeRateTransformer;
use FireflyIII\Transformers\CurrencyTransformer;
use FireflyIII\Transformers\RecurrenceTransformer;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
@@ -47,6 +74,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class CurrencyController extends Controller
{
use AccountFilter, TransactionFilter;
/** @var CurrencyRepositoryInterface The currency repository */
private $repository;
/** @var UserRepositoryInterface The user repository */
@@ -73,6 +101,241 @@ class CurrencyController extends Controller
);
}
/**
* Display a list of accounts.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function accounts(Request $request, TransactionCurrency $currency): JsonResponse
{
// 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->mapAccountTypes($this->parameters->get('type'));
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$unfiltered = $accountRepository->getAccountsByType($types);
// filter list on currency preference:
$collection = $unfiltered->filter(
function (Account $account) use ($currency, $accountRepository) {
$currencyId = (int)$accountRepository->getMetaValue($account, 'currency_id');
return $currencyId === $currency->id;
}
);
$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.currencies.accounts', [$currency->code]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($accounts, $transformer, 'accounts');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function availableBudgets(Request $request, TransactionCurrency $currency): JsonResponse
{
/** @var User $admin */
$admin = auth()->user();
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of available budgets. Count it and split it.
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser($admin);
$unfiltered = $repository->getAvailableBudgets();
// filter list.
$collection = $unfiltered->filter(
function (AvailableBudget $availableBudget) use ($currency) {
return $availableBudget->transaction_currency_id === $currency->id;
}
);
$count = $collection->count();
$availableBudgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($availableBudgets, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.available_budgets', [$currency->code]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($availableBudgets, $transformer, 'available_budgets');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all bills
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function bills(Request $request, TransactionCurrency $currency): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$paginator = $repository->getPaginator($pageSize);
/** @var Collection $bills */
$unfiltered = $paginator->getCollection();
// filter and paginate list:
$collection = $unfiltered->filter(
function (Bill $bill) use ($currency) {
return $bill->transaction_currency_id === $currency->id;
}
);
$count = $collection->count();
$bills = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.bills', [$currency->code]) . $this->buildParams());
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($bills, $transformer, 'bills');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all budget limits
*
* @param Request $request
*
* @return JsonResponse
*/
public function budgetLimits(Request $request, TransactionCurrency $currency): JsonResponse
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$unfiltered = $repository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end'));
// TODO replace this
// filter budget limits on currency ID
$collection = $unfiltered->filter(
function (BudgetLimit $budgetLimit) use ($currency) {
return $budgetLimit->transaction_currency_id === $currency->id;
}
);
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.budget_limits', [$currency->code]) . $this->buildParams());
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($budgetLimits, $transformer, 'budget_limits');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show a list of known exchange rates
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function cer(Request $request, TransactionCurrency $currency): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$collection = $this->repository->getExchangeRates($currency);
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$count = $collection->count();
$exchangeRates = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($exchangeRates, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.cer', [$currency->code]) . $this->buildParams());
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var CurrencyExchangeRateTransformer $transformer */
$transformer = app(CurrencyExchangeRateTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($exchangeRates, $transformer, 'currency_exchange_rates');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Remove the specified resource from storage.
*
@@ -90,7 +353,7 @@ class CurrencyController extends Controller
// access denied:
throw new FireflyException('No access to method, user is not owner.'); // @codeCoverageIgnore
}
if (!$this->repository->canDeleteCurrency($currency)) {
if ($this->repository->currencyInUse($currency)) {
throw new FireflyException('No access to method, currency is in use.'); // @codeCoverageIgnore
}
$this->repository->destroy($currency);
@@ -98,6 +361,66 @@ class CurrencyController extends Controller
return response()->json([], 204);
}
/**
* Disable a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function disable(Request $request, TransactionCurrency $currency): JsonResponse
{
// must be unused.
if ($this->repository->currencyInUse($currency)) {
return response()->json([], 409);
}
$this->repository->disable($currency);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Enable a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function enable(Request $request, TransactionCurrency $currency): JsonResponse
{
$this->repository->enable($currency);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Display a listing of the resource.
*
@@ -108,7 +431,7 @@ class CurrencyController extends Controller
public function index(Request $request): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$collection = $this->repository->get();
$collection = $this->repository->getAll();
$count = $collection->count();
// slice them:
$currencies = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
@@ -122,12 +445,156 @@ class CurrencyController extends Controller
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
$resource = new FractalCollection($currencies, new CurrencyTransformer($this->parameters), 'currencies');
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($currencies, $transformer, 'currencies');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Make the currency a default currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function makeDefault(Request $request, TransactionCurrency $currency): JsonResponse
{
$this->repository->enable($currency);
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$this->parameters->set('defaultCurrency', $currency);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all recurring transactions.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function recurrences(Request $request, TransactionCurrency $currency): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
/** @var RecurringRepositoryInterface $repository */
$repository = app(RecurringRepositoryInterface::class);
$unfiltered = $repository->getAll();
// filter selection
$collection = $unfiltered->filter(
function (Recurrence $recurrence) use ($currency) {
/** @var RecurrenceTransaction $transaction */
foreach ($recurrence->recurrenceTransactions as $transaction) {
if ($transaction->transaction_currency_id === $currency->id || $transaction->foreign_currency_id === $currency->id) {
return $recurrence;
}
}
return null;
}
);
$count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.recurrences', [$currency->code]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'recurrences');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all of them.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return JsonResponse]
*/
public function rules(Request $request, TransactionCurrency $currency): JsonResponse
{
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
/** @var RuleRepositoryInterface $repository */
$repository = app(RuleRepositoryInterface::class);
$unfiltered = $repository->getAll();
$collection = $unfiltered->filter(
function (Rule $rule) use ($currency) {
/** @var RuleTrigger $trigger */
foreach ($rule->ruleTriggers as $trigger) {
if ('currency_is' === $trigger->trigger_type && $currency->name === $trigger->trigger_value) {
return $rule;
}
}
return null;
}
);
$count = $collection->count();
$rules = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rules.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($rules, $transformer, 'rules');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show a currency.
@@ -140,16 +607,16 @@ class CurrencyController extends Controller
public function show(Request $request, TransactionCurrency $currency): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
$resource = new Item($currency, new CurrencyTransformer($this->parameters), 'currencies');
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -177,7 +644,11 @@ class CurrencyController extends Controller
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
$resource = new Item($currency, new CurrencyTransformer($this->parameters), 'currencies');
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -185,6 +656,57 @@ class CurrencyController extends Controller
}
/**
* Show all transactions.
*
* @param Request $request
*
* @param TransactionCurrency $currency
*
* @return JsonResponse
*/
public function transactions(Request $request, TransactionCurrency $currency): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setCurrency($currency);
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.currencies.transactions', [$currency->code]) . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update a currency.
@@ -211,7 +733,11 @@ class CurrencyController extends Controller
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
$resource = new Item($currency, new CurrencyTransformer($this->parameters), 'currencies');
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -92,6 +92,7 @@ class CurrencyExchangeRateController extends Controller
$this->parameters->set('from', $fromCurrency->code);
$this->parameters->set('to', $toCurrency->code);
$this->parameters->set('date', $dateObj->format('Y-m-d'));
$this->parameters->set('amount', $request->get('amount'));
$rate = $this->repository->getExchangeRate($fromCurrency, $toCurrency, $dateObj);
if (null === $rate) {
@@ -103,8 +104,10 @@ class CurrencyExchangeRateController extends Controller
$service->setUser($admin);
$rate = $service->getRate($fromCurrency, $toCurrency, $dateObj);
}
$resource = new Item($rate, new CurrencyExchangeRateTransformer($this->parameters), 'currency_exchange_rates');
/** @var CurrencyExchangeRateTransformer $transformer */
$transformer = app(CurrencyExchangeRateTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($rate, $transformer, 'currency_exchange_rates');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}

View File

@@ -0,0 +1,184 @@
<?php
/**
* ImportController.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\Api\V1\Controllers;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\ImportJobTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
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;
/**
* Class ImportController
*/
class ImportController extends Controller
{
use TransactionFilter;
/** @var ImportJobRepositoryInterface Import job repository. */
private $repository;
/**
* LinkTypeController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
*/
public function listAll(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$importJobs = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($importJobs, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.import.list') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var ImportJobTransformer $transformer */
$transformer = app(ImportJobTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($importJobs, $transformer, 'import_jobs');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param ImportJob $importJob
*
* @return JsonResponse
*/
public function show(Request $request, ImportJob $importJob): JsonResponse
{
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var ImportJobTransformer $transformer */
$transformer = app(ImportJobTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($importJob, $transformer, 'import_jobs');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show all transactions
*
* @param ImportJob $importJob
*
* @return JsonResponse
*/
public function transactions(Request $request, ImportJob $importJob): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$tag = $importJob->tag;
$transactions = new Collection();
$paginator = new LengthAwarePaginator($transactions, 0, $pageSize);
$paginator->setPath(route('api.v1.import.transactions', [$importJob->key]) . $this->buildParams());
if (null !== $tag) {
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setTag($tag);
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
}
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@@ -25,10 +25,15 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\LinkTypeRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\LinkType;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\LinkTypeTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -46,6 +51,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class LinkTypeController extends Controller
{
use TransactionFilter;
/** @var LinkTypeRepositoryInterface The link type repository */
private $repository;
@@ -114,7 +120,12 @@ class LinkTypeController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($linkTypes, new LinkTypeTransformer($this->parameters), 'link_types');
/** @var LinkTypeTransformer $transformer */
$transformer = app(LinkTypeTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($linkTypes, $transformer, 'link_types');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -132,14 +143,13 @@ class LinkTypeController extends Controller
public function show(Request $request, LinkType $linkType): JsonResponse
{
$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($linkType, new LinkTypeTransformer($this->parameters), 'link_types');
/** @var LinkTypeTransformer $transformer */
$transformer = app(LinkTypeTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($linkType, $transformer, 'link_types');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -168,12 +178,69 @@ class LinkTypeController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($linkType, new LinkTypeTransformer($this->parameters), 'link_types');
/** @var LinkTypeTransformer $transformer */
$transformer = app(LinkTypeTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($linkType, $transformer, 'link_types');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Delete the resource.
*
* @param LinkType $linkType
*
* @return JsonResponse
*/
public function transactions(Request $request, LinkType $linkType): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// whatever is returned by the query, it must be part of these journals:
$journalIds = $this->repository->getJournalIds($linkType);
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setJournalIds($journalIds);
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update object.
*
@@ -202,7 +269,11 @@ class LinkTypeController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($linkType, new LinkTypeTransformer($this->parameters), 'link_types');
/** @var LinkTypeTransformer $transformer */
$transformer = app(LinkTypeTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($linkType, $transformer, 'link_types');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -27,6 +27,7 @@ use FireflyIII\Api\V1\Requests\PiggyBankRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\PiggyBankEventTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -110,7 +111,47 @@ class PiggyBankController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($piggyBanks, new PiggyBankTransformer($this->parameters), 'piggy_banks');
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function piggyBankEvents(Request $request, PiggyBank $piggyBank): JsonResponse
{
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$collection = $this->repository->getEvents($piggyBank);
$count = $collection->count();
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy_banks.events', [$piggyBank->id]) . $this->buildParams());
/** @var PiggyBankEventTransformer $transformer */
$transformer = app(PiggyBankEventTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($events, $transformer, 'piggy_bank_events');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -128,14 +169,14 @@ class PiggyBankController extends Controller
public function show(Request $request, PiggyBank $piggyBank): JsonResponse
{
$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($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -157,7 +198,11 @@ class PiggyBankController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -180,7 +225,11 @@ class PiggyBankController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -24,7 +24,9 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\PreferenceRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Transformers\PreferenceTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -41,6 +43,34 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class PreferenceController extends Controller
{
/**
* LinkTypeController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($user);
// an important fallback is that the frontPageAccount array gets refilled automatically
// when it turns up empty.
$frontPageAccounts = app('preferences')->getForUser($user, 'frontPageAccounts', [])->data;
if (\count($frontPageAccounts) === 0) {
/** @var Collection $accounts */
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
$accountIds = $accounts->pluck('id')->toArray();
app('preferences')->setForUser($user, 'frontPageAccounts', $accountIds);
}
return $next($request);
}
);
}
/**
* List all of them.
*
@@ -51,12 +81,13 @@ class PreferenceController extends Controller
public function index(Request $request): JsonResponse
{
/** @var User $user */
$user = auth()->user();
$available = [
$user = auth()->user();
$available = [
'language', 'customFiscalYear', 'fiscalYearStart', 'currencyPreference',
'transaction_journal_optional_fields', 'frontPageAccounts', 'viewRange',
'listPageSize, twoFactorAuthEnabled',
];
$preferences = new Collection;
foreach ($available as $name) {
$pref = app('preferences')->getForUser($user, $name);
@@ -71,7 +102,12 @@ class PreferenceController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($preferences, new PreferenceTransformer($this->parameters), 'preferences');
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($preferences, $transformer, 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -79,12 +115,13 @@ class PreferenceController extends Controller
}
/**
* List single resource.
* Return a single preference by name.
*
* @param Request $request
* @param Preference $preference
*
* @return JsonResponse
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function show(Request $request, Preference $preference): JsonResponse
{
@@ -94,10 +131,13 @@ class PreferenceController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($preference, new PreferenceTransformer($this->parameters), 'preferences');
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($preference, $transformer, 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
@@ -137,7 +177,11 @@ class PreferenceController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($result, new PreferenceTransformer($this->parameters), 'preferences');
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($result, $transformer, 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -24,9 +24,16 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\RecurrenceRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\RecurrenceTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -36,12 +43,14 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Log;
/**
* Class RecurrenceController
*/
class RecurrenceController extends Controller
{
use TransactionFilter;
/** @var RecurringRepositoryInterface The recurring transaction repository */
private $repository;
@@ -106,7 +115,12 @@ class RecurrenceController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($piggyBanks, new RecurrenceTransformer($this->parameters), 'recurrences');
/** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'recurrences');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -124,14 +138,14 @@ class RecurrenceController extends Controller
public function show(Request $request, Recurrence $recurrence): JsonResponse
{
$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($recurrence, new RecurrenceTransformer($this->parameters), 'recurrences');
/** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($recurrence, $transformer, 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -151,11 +165,94 @@ class RecurrenceController extends Controller
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($recurrence, new RecurrenceTransformer($this->parameters), 'recurrences');
/** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($recurrence, $transformer, 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show transactions for this recurrence.
*
* @param Request $request
* @param Recurrence $recurrence
*
* @return JsonResponse
*/
public function transactions(Request $request, Recurrence $recurrence): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// whatever is returned by the query, it must be part of these journals:
$journalIds = $this->repository->getJournalIds($recurrence);
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setJournalIds($journalIds);
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @return JsonResponse
* @throws FireflyException
*/
public function trigger(): JsonResponse
{
/** @var RecurringCronjob $recurring */
$recurring = app(RecurringCronjob::class);
try {
$result = $recurring->fire();
} catch (FireflyException $e) {
Log::error($e->getMessage());
throw new FireflyException('Could not fire recurring cron job.');
}
if (false === $result) {
return response()->json([], 204);
}
if (true === $result) {
return response()->json([], 200);
}
return response()->json([], 418); // @codeCoverageIgnore
}
/**
* Update single recurrence.
*
@@ -171,8 +268,11 @@ class RecurrenceController extends Controller
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($category, new RecurrenceTransformer($this->parameters), 'recurrences');
$resource = new Item($category, $transformer, 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -23,25 +23,36 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use FireflyIII\Api\V1\Requests\RuleRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\TransactionRules\TransactionMatcher;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
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 Log;
/**
* Class RuleController
*/
class RuleController extends Controller
{
/** @var AccountRepositoryInterface Account repository */
private $accountRepository;
/** @var RuleRepositoryInterface The rule repository */
private $ruleRepository;
@@ -59,6 +70,9 @@ class RuleController extends Controller
$this->ruleRepository = app(RuleRepositoryInterface::class);
$this->ruleRepository->setUser($user);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUser($user);
return $next($request);
}
);
@@ -105,7 +119,12 @@ class RuleController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($rules, new RuleTransformer($this->parameters), 'rules');
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($rules, $transformer, 'rules');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -123,14 +142,14 @@ class RuleController extends Controller
public function show(Request $request, Rule $rule): JsonResponse
{
$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($rule, new RuleTransformer($this->parameters), 'rules');
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($rule, $transformer, 'rules');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -150,11 +169,127 @@ class RuleController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($rule, new RuleTransformer($this->parameters), 'rules');
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($rule, $transformer, 'rules');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Rule $rule
*
* @return JsonResponse
* @throws FireflyException
*/
public function testRule(Request $request, Rule $rule): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$page = 0 === (int)$request->query('page') ? 1 : (int)$request->query('page');
$startDate = null === $request->query('start_date') ? null : Carbon::createFromFormat('Y-m-d', $request->query('start_date'));
$endDate = null === $request->query('end_date') ? null : Carbon::createFromFormat('Y-m-d', $request->query('end_date'));
$searchLimit = 0 === (int)$request->query('search_limit') ? (int)config('firefly.test-triggers.limit') : (int)$request->query('search_limit');
$triggerLimit = 0 === (int)$request->query('triggered_limit') ? (int)config('firefly.test-triggers.range') : (int)$request->query('triggered_limit');
$accountList = '' === (string)$request->query('accounts') ? [] : explode(',', $request->query('accounts'));
$accounts = new Collection;
foreach ($accountList as $accountId) {
Log::debug(sprintf('Searching for asset account with id "%s"', $accountId));
$account = $this->accountRepository->findNull((int)$accountId);
if (null !== $account && AccountType::ASSET === $account->accountType->type) {
Log::debug(sprintf('Found account #%d ("%s") and its an asset account', $account->id, $account->name));
$accounts->push($account);
}
if (null === $account) {
Log::debug(sprintf('No asset account with id "%s"', $accountId));
}
}
/** @var Rule $rule */
Log::debug(sprintf('Now testing rule #%d, "%s"', $rule->id, $rule->title));
/** @var TransactionMatcher $matcher */
$matcher = app(TransactionMatcher::class);
// set all parameters:
$matcher->setRule($rule);
$matcher->setStartDate($startDate);
$matcher->setEndDate($endDate);
$matcher->setSearchLimit($searchLimit);
$matcher->setTriggeredLimit($triggerLimit);
$matcher->setAccounts($accounts);
$matchingTransactions = $matcher->findTransactionsByRule();
$matchingTransactions = $matchingTransactions->unique('id');
// make paginator out of results.
$count = $matchingTransactions->count();
$transactions = $matchingTransactions->slice(($page - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($transactions, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rules.test', [$rule->id]) . $this->buildParams());
// resulting list is presented as JSON thing.
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($matchingTransactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Execute the given rule group on a set of existing transactions.
*
* @param Request $request
* @param Rule $rule
*
* @return JsonResponse
*/
public function triggerRule(Request $request, Rule $rule): JsonResponse
{
// Get parameters specified by the user
/** @var User $user */
$user = auth()->user();
$startDate = new Carbon($request->get('start_date'));
$endDate = new Carbon($request->get('end_date'));
$accountList = '' === (string)$request->query('accounts') ? [] : explode(',', $request->query('accounts'));
$accounts = new Collection;
foreach ($accountList as $accountId) {
Log::debug(sprintf('Searching for asset account with id "%s"', $accountId));
$account = $this->accountRepository->findNull((int)$accountId);
if (null !== $account && $this->accountRepository->isAsset($account)) {
Log::debug(sprintf('Found account #%d ("%s") and its an asset account', $account->id, $account->name));
$accounts->push($account);
}
if (null === $account) {
Log::debug(sprintf('No asset account with id "%s"', $accountId));
}
}
// Create a job to do the work asynchronously
$job = new ExecuteRuleOnExistingTransactions($rule);
// Apply parameters to the job
$job->setUser($user);
$job->setAccounts($accounts);
$job->setStartDate($startDate);
$job->setEndDate($endDate);
// Dispatch a new job to execute it in a queue
$this->dispatch($job);
return response()->json([], 204);
}
/**
* Update a rule.
*
@@ -170,7 +305,11 @@ class RuleController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($rule, new RuleTransformer($this->parameters), 'rules');
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($rule, $transformer, 'rules');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -23,19 +23,30 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use FireflyIII\Api\V1\Requests\RuleGroupRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\TransactionMatcher;
use FireflyIII\Transformers\RuleGroupTransformer;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
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 Log;
/**
@@ -43,6 +54,8 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class RuleGroupController extends Controller
{
/** @var AccountRepositoryInterface Account repository */
private $accountRepository;
/** @var RuleGroupRepositoryInterface The rule group repository */
private $ruleGroupRepository;
@@ -60,6 +73,9 @@ class RuleGroupController extends Controller
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
$this->ruleGroupRepository->setUser($user);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUser($user);
return $next($request);
}
);
@@ -106,12 +122,55 @@ class RuleGroupController extends Controller
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($ruleGroups, new RuleGroupTransformer($this->parameters), 'rule_groups');
/** @var RuleGroupTransformer $transformer */
$transformer = app(RuleGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($ruleGroups, $transformer, 'rule_groups');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param RuleGroup $group
*
* @return JsonResponse
*/
public function rules(Request $request, RuleGroup $group): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->ruleGroupRepository->getRules($group);
$count = $collection->count();
$rules = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rule_groups.rules', [$group->id]) . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($rules, $transformer, 'rules');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
@@ -123,14 +182,14 @@ class RuleGroupController extends Controller
public function show(Request $request, RuleGroup $ruleGroup): JsonResponse
{
$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($ruleGroup, new RuleGroupTransformer($this->parameters), 'rule_groups');
/** @var RuleGroupTransformer $transformer */
$transformer = app(RuleGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($ruleGroup, $transformer, 'rule_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -150,14 +209,128 @@ class RuleGroupController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($ruleGroup, new RuleGroupTransformer($this->parameters), 'rule_groups');
/** @var RuleGroupTransformer $transformer */
$transformer = app(RuleGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($ruleGroup, $transformer, 'rule_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param RuleGroup $group
*
* @return JsonResponse
* @throws FireflyException
*/
public function testGroup(Request $request, RuleGroup $group): JsonResponse
{
Log::debug('Now in testGroup()');
/** @var Collection $rules */
$rules = $this->ruleGroupRepository->getActiveRules($group);
if (0 === $rules->count()) {
throw new FireflyException('No rules in this rule group.');
}
$parameters = $this->getTestParameters($request);
$accounts = $this->getAccountParameter($parameters['account_list']);
$matchingTransactions = new Collection;
Log::debug(sprintf('Going to test %d rules', $rules->count()));
/** @var Rule $rule */
foreach ($rules as $rule) {
Log::debug(sprintf('Now testing rule #%d, "%s"', $rule->id, $rule->title));
/** @var TransactionMatcher $matcher */
$matcher = app(TransactionMatcher::class);
// set all parameters:
$matcher->setRule($rule);
$matcher->setStartDate($parameters['start_date']);
$matcher->setEndDate($parameters['end_date']);
$matcher->setSearchLimit($parameters['search_limit']);
$matcher->setTriggeredLimit($parameters['trigger_limit']);
$matcher->setAccounts($accounts);
$result = $matcher->findTransactionsByRule();
$matchingTransactions = $result->merge($matchingTransactions);
}
$matchingTransactions = $matchingTransactions->unique('id');
// make paginator out of results.
$count = $matchingTransactions->count();
$transactions = $matchingTransactions->slice(($parameters['page'] - 1) * $parameters['page_size'], $parameters['page_size']);
// make paginator:
$paginator = new LengthAwarePaginator($transactions, $count, $parameters['page_size'], $parameters['page']);
$paginator->setPath(route('api.v1.rule_groups.test', [$group->id]) . $this->buildParams());
// resulting list is presented as JSON thing.
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($matchingTransactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Execute the given rule group on a set of existing transactions.
*
* @param Request $request
* @param RuleGroup $group
*
* @return JsonResponse
*/
public function triggerGroup(Request $request, RuleGroup $group): JsonResponse
{
// Get parameters specified by the user
/** @var User $user */
$user = auth()->user();
$startDate = new Carbon($request->get('start_date'));
$endDate = new Carbon($request->get('end_date'));
$accountList = '' === (string)$request->query('accounts') ? [] : explode(',', $request->query('accounts'));
$accounts = new Collection;
foreach ($accountList as $accountId) {
Log::debug(sprintf('Searching for asset account with id "%s"', $accountId));
$account = $this->accountRepository->findNull((int)$accountId);
if (null !== $account && AccountType::ASSET === $account->accountType->type) {
Log::debug(sprintf('Found account #%d ("%s") and its an asset account', $account->id, $account->name));
$accounts->push($account);
}
if (null === $account) {
Log::debug(sprintf('No asset account with id "%s"', $accountId));
}
}
/** @var Collection $rules */
$rules = $this->ruleGroupRepository->getActiveRules($group);
foreach ($rules as $rule) {
// Create a job to do the work asynchronously
$job = new ExecuteRuleOnExistingTransactions($rule);
// Apply parameters to the job
$job->setUser($user);
$job->setAccounts($accounts);
$job->setStartDate($startDate);
$job->setEndDate($endDate);
// Dispatch a new job to execute it in a queue
$this->dispatch($job);
}
return response()->json([], 204);
}
/**
* Update a rule group.
* TODO update order of rule group
*
* @param RuleGroupRequest $request
* @param RuleGroup $ruleGroup
@@ -171,9 +344,58 @@ class RuleGroupController extends Controller
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($ruleGroup, new RuleGroupTransformer($this->parameters), 'rule_groups');
/** @var RuleGroupTransformer $transformer */
$transformer = app(RuleGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($ruleGroup, $transformer, 'rule_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param array $accounts
*
* @return Collection
*/
private function getAccountParameter(array $accounts): Collection
{
$return = new Collection;
foreach ($accounts as $accountId) {
Log::debug(sprintf('Searching for asset account with id "%s"', $accountId));
$account = $this->accountRepository->findNull((int)$accountId);
if (null !== $account && AccountType::ASSET === $account->accountType->type) {
Log::debug(sprintf('Found account #%d ("%s") and its an asset account', $account->id, $account->name));
$return->push($account);
}
if (null === $account) {
Log::debug(sprintf('No asset account with id "%s"', $accountId));
}
}
return $return;
}
/**
* @param Request $request
*
* @return array
*/
private function getTestParameters(Request $request): array
{
return [
'page_size' => (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data,
'page' => 0 === (int)$request->query('page') ? 1 : (int)$request->query('page'),
'start_date' => null === $request->query('start_date') ? null : Carbon::createFromFormat('Y-m-d', $request->query('start_date')),
'end_date' => null === $request->query('end_date') ? null : Carbon::createFromFormat('Y-m-d', $request->query('end_date')),
'search_limit' => 0 === (int)$request->query('search_limit') ? (int)config('firefly.test-triggers.limit') : (int)$request->query('search_limit'),
'trigger_limit' => 0 === (int)$request->query('triggered_limit')
? (int)config('firefly.test-triggers.range')
: (int)$request->query(
'triggered_limit'
),
'account_list' => '' === (string)$request->query('accounts') ? [] : explode(',', $request->query('accounts')),
];
}
}

View File

@@ -0,0 +1,413 @@
<?php
/**
* SummaryController.php
* Copyright (c) 2019 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\Api\V1\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Report\NetWorthInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
/**
* Class SummaryController
*/
class SummaryController extends Controller
{
/** @var AccountRepositoryInterface */
private $accountRepository;
/** @var BillRepositoryInterface */
private $billRepository;
/** @var BudgetRepositoryInterface */
private $budgetRepository;
/** @var CurrencyRepositoryInterface */
private $currencyRepos;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->billRepository = app(BillRepositoryInterface::class);
$this->budgetRepository = app(BudgetRepositoryInterface::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->billRepository->setUser($user);
$this->currencyRepos->setUser($user);
$this->budgetRepository->setUser($user);
$this->accountRepository->setUser($user);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function basic(Request $request): JsonResponse
{
// parameters for boxes:
$start = (string)$request->get('start');
$end = (string)$request->get('end');
if ('' === $start || '' === $end) {
throw new FireflyException('Start and end are mandatory parameters.');
}
$start = Carbon::createFromFormat('Y-m-d', $start);
$end = Carbon::createFromFormat('Y-m-d', $end);
// balance information:
$balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$networthData = $this->getNetWorthInfo($start, $end);
$total = array_merge($balanceData, $billData, $spentData, $networthData);
// TODO: liabilities with icon line-chart
return response()->json($total);
}
/**
* Check if date is outside session range.
*
* @param Carbon $date
*
* @param Carbon $start
* @param Carbon $end
*
* @return bool
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
{
$result = false;
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
$result = true;
}
// start and end in the past? use $end
if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
$result = true;
}
return $result;
}
/**
* This method will scroll through the results of the spentInPeriodMc() array and return the correct info.
*
* @param array $spentInfo
* @param TransactionCurrency $currency
*
* @return float
*/
private function findInSpentArray(array $spentInfo, TransactionCurrency $currency): float
{
foreach ($spentInfo as $array) {
if ($array['currency_id'] === $currency->id) {
return $array['amount'];
}
}
return 0.0;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function getBalanceInformation(Carbon $start, Carbon $end): array
{
// prep some arrays:
$incomes = [];
$expenses = [];
$sums = [];
$return = [];
// collect income of user:
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes([TransactionType::DEPOSIT])
->withOpposingAccount();
$set = $collector->getTransactions();
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$currencyId = (int)$transaction->transaction_currency_id;
$incomes[$currencyId] = $incomes[$currencyId] ?? '0';
$incomes[$currencyId] = bcadd($incomes[$currencyId], $transaction->transaction_amount);
$sums[$currencyId] = $sums[$currencyId] ?? '0';
$sums[$currencyId] = bcadd($sums[$currencyId], $transaction->transaction_amount);
}
// collect expenses:
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes([TransactionType::WITHDRAWAL])
->withOpposingAccount();
$set = $collector->getTransactions();
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$currencyId = (int)$transaction->transaction_currency_id;
$expenses[$currencyId] = $expenses[$currencyId] ?? '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $transaction->transaction_amount);
$sums[$currencyId] = $sums[$currencyId] ?? '0';
$sums[$currencyId] = bcadd($sums[$currencyId], $transaction->transaction_amount);
}
// format amounts:
$keys = array_keys($sums);
foreach ($keys as $currencyId) {
$currency = $this->currencyRepos->findNull($currencyId);
if (null === $currency) {
continue;
}
// create objects for big array.
$return[] = [
'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => round($sums[$currencyId] ?? 0, $currency->decimal_places),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId] ?? '0', false),
'local_icon' => 'balance-scale',
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false) .
' + ' . app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
];
$return[] = [
'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => round($expenses[$currencyId] ?? 0, $currency->decimal_places),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false),
'local_icon' => 'balance-scale',
'sub_title' => '',
];
$return[] = [
'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => round($incomes[$currencyId] ?? 0, $currency->decimal_places),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
'local_icon' => 'balance-scale',
'sub_title' => '',
];
}
return $return;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function getBillInformation(Carbon $start, Carbon $end): array
{
/*
* Since both this method and the chart use the exact same data, we can suffice
* with calling the one method in the bill repository that will get this amount.
*/
$paidAmount = $this->billRepository->getBillsPaidInRangePerCurrency($start, $end);
$unpaidAmount = $this->billRepository->getBillsUnpaidInRangePerCurrency($start, $end);
$return = [];
foreach ($paidAmount as $currencyId => $amount) {
$amount = bcmul($amount, '-1');
$currency = $this->currencyRepos->findNull((int)$currencyId);
if (null === $currency) {
continue;
}
$return[] = [
'key' => sprintf('bills-paid-in-%s', $currency->code),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => round($amount, $currency->decimal_places),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $amount, false),
'local_icon' => 'check',
'sub_title' => '',
];
}
foreach ($unpaidAmount as $currencyId => $amount) {
$amount = bcmul($amount, '-1');
$currency = $this->currencyRepos->findNull((int)$currencyId);
if (null === $currency) {
continue;
}
$return[] = [
'key' => sprintf('bills-unpaid-in-%s', $currency->code),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => round($amount, $currency->decimal_places),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $amount, false),
'local_icon' => 'calendar-o',
'sub_title' => '',
];
}
return $return;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
{
$return = [];
$today = new Carbon;
$available = $this->budgetRepository->getAvailableBudgetWithCurrency($start, $end);
$budgets = $this->budgetRepository->getActiveBudgets();
$spentInfo = $this->budgetRepository->spentInPeriodMc($budgets, new Collection, $start, $end);
foreach ($available as $currencyId => $amount) {
$currency = $this->currencyRepos->findNull($currencyId);
if (null === $currency) {
continue;
}
$spentInCurrency = (string)$this->findInSpentArray($spentInfo, $currency);
$leftToSpend = bcadd($amount, $spentInCurrency);
$days = $today->diffInDays($end) + 1;
$perDay = '0';
if (0 !== $days && bccomp($leftToSpend, '0') > -1) {
$perDay = bcdiv($leftToSpend, (string)$days);
}
$return[] = [
'key' => sprintf('left-to-spend-in-%s', $currency->code),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => round($leftToSpend, $currency->decimal_places),
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $leftToSpend, false),
'local_icon' => 'money',
'sub_title' => (string)trans('firefly.box_spend_per_day', ['amount' => app('amount')->formatAnything($currency, $perDay, false)]),
];
}
return $return;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function getNetWorthInfo(Carbon $start, Carbon $end): array
{
$date = Carbon::create()->startOfDay();
// start and end in the future? use $end
if ($this->notInDateRange($date, $start, $end)) {
/** @var Carbon $date */
$date = session('end', Carbon::now()->endOfMonth());
}
/** @var NetWorthInterface $netWorthHelper */
$netWorthHelper = app(NetWorthInterface::class);
$netWorthHelper->setUser(auth()->user());
$allAccounts = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE]);
// filter list on preference of being included.
$filtered = $allAccounts->filter(
function (Account $account) {
$includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
return null === $includeNetWorth ? true : '1' === $includeNetWorth;
}
);
$netWorthSet = $netWorthHelper->getNetWorthByCurrency($filtered, $date);
$return = [];
foreach ($netWorthSet as $index => $data) {
/** @var TransactionCurrency $currency */
$currency = $data['currency'];
$amount = round($data['balance'], $currency->decimal_places);
if ($amount === 0.0) {
continue;
}
// return stuff
$return[] = [
'key' => sprintf('net-worth-in-%s', $currency->code),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $amount,
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $data['balance'], false),
'local_icon' => 'line-chart',
'sub_title' => '',
];
}
return $return;
}
}

View File

@@ -0,0 +1,298 @@
<?php
/**
* TagController.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\Api\V1\Controllers;
use Carbon\Carbon;
use FireflyIII\Api\V1\Requests\TagRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\TagTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
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;
/**
* Class TagController
*/
class TagController extends Controller
{
use TransactionFilter;
/** @var TagRepositoryInterface The tag repository */
private $repository;
/**
* RuleController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(TagRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function cloud(Request $request): JsonResponse
{
// parameters for cloud:
$start = (string)$request->get('start');
$end = (string)$request->get('end');
if ('' === $start || '' === $end) {
throw new FireflyException('Start and end are mandatory parameters.');
}
$start = Carbon::createFromFormat('Y-m-d', $start);
$end = Carbon::createFromFormat('Y-m-d', $end);
// get all tags:
$tags = $this->repository->get();
$min = null;
$max = 0;
$return = [
'tags' => [],
];
/** @var Tag $tag */
foreach ($tags as $tag) {
$earned = (float)$this->repository->earnedInPeriod($tag, $start, $end);
$spent = (float)$this->repository->spentInPeriod($tag, $start, $end);
$size = ($spent * -1) + $earned;
$min = $min ?? $size;
if ($size > 0) {
$max = $size > $max ? $size : $max;
$return['tags'][] = [
'tag' => $tag->tag,
'id' => $tag->id,
'size' => $size,
];
}
}
foreach ($return['tags'] as $index => $info) {
$return['tags'][$index]['relative'] = $return['tags'][$index]['size'] / $max;
}
$return['min'] = $min;
$return['max'] = $max;
return response()->json($return);
}
/**
* Delete the resource.
*
* @param Tag $tag
*
* @return JsonResponse
*/
public function delete(Tag $tag): JsonResponse
{
$this->repository->destroy($tag);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$rules = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.tags.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var TagTransformer $transformer */
$transformer = app(TagTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($rules, $transformer, 'tags');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param Tag $tag
*
* @return JsonResponse
*/
public function show(Request $request, Tag $tag): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var TagTransformer $transformer */
$transformer = app(TagTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($tag, $transformer, 'tags');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param TagRequest $request
*
* @return JsonResponse
*/
public function store(TagRequest $request): JsonResponse
{
$rule = $this->repository->store($request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var TagTransformer $transformer */
$transformer = app(TagTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($rule, $transformer, 'tags');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show all transactions.
*
* @param Request $request
* @param Tag $tag
*
* @return JsonResponse
*/
public function transactions(Request $request, Tag $tag): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
$collector->setTag($tag);
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
if (null !== $this->parameters->get('start') && 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->getPaginatedTransactions();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update a rule.
*
* @param TagRequest $request
* @param Tag $tag
*
* @return JsonResponse
*/
public function update(TagRequest $request, Tag $tag): JsonResponse
{
$rule = $this->repository->update($tag, $request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
/** @var TagTransformer $transformer */
$transformer = app(TagTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($rule, $transformer, 'tags');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@@ -35,6 +35,9 @@ use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -51,6 +54,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class TransactionController extends Controller
{
use TransactionFilter;
/** @var JournalRepositoryInterface The journal repository */
private $repository;
@@ -75,6 +79,30 @@ class TransactionController extends Controller
);
}
/**
* @param Request $request
* @param Transaction $transaction
*
* @return JsonResponse
*/
public function attachments(Request $request, Transaction $transaction): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$attachments = $this->repository->getAttachmentsByTr($transaction);
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Remove the specified resource from storage.
*
@@ -103,7 +131,7 @@ class TransactionController extends Controller
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTypes($this->parameters->get('type'));
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
@@ -129,33 +157,54 @@ class TransactionController extends Controller
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, '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 JsonResponse
*/
public function piggyBankEvents(Request $request, Transaction $transaction): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$events = $this->repository->getPiggyBankEventsByTr($transaction);
/** @var PiggyBankEventTransformer $transformer */
$transformer = app(PiggyBankEventTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($events, $transformer, 'piggy_bank_events');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show a single transaction.
*
* @param Request $request
* @param Transaction $transaction
* @param string $include
*
* @return JsonResponse
*/
public function show(Request $request, Transaction $transaction, string $include = null): JsonResponse
public function show(Request $request, Transaction $transaction): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $include ?? '';
$include = $request->get('include') ?? $include;
$manager->parseIncludes($include);
// collect transactions using the journal collector
$collector = app(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
@@ -169,11 +218,14 @@ class TransactionController extends Controller
$collector->addFilter(PositiveAmountFilter::class);
}
if (!($transactionType === TransactionType::WITHDRAWAL)) {
$collector->addFilter(NegativeAmountFilter::class);
$collector->addFilter(NegativeAmountFilter::class); // @codeCoverageIgnore
}
$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -194,16 +246,12 @@ class TransactionController extends Controller
$data['user'] = auth()->user()->id;
$journal = $repository->store($data);
event(new StoredTransactionJournal($journal, 0));
event(new StoredTransactionJournal($journal));
$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(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
@@ -221,7 +269,12 @@ class TransactionController extends Controller
}
$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -247,10 +300,6 @@ class TransactionController extends Controller
event(new UpdatedTransactionJournal($journal));
// 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(TransactionCollectorInterface::class);
@@ -269,45 +318,14 @@ class TransactionController extends Controller
}
$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
/** @var TransactionTransformer $transformer */
$transformer = app(TransactionTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* All the types you can request.
*
* @param string $type
*
* @return array
*/
private function mapTypes(string $type): array
{
$types = [
'all' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,],
'withdrawal' => [TransactionType::WITHDRAWAL,],
'withdrawals' => [TransactionType::WITHDRAWAL,],
'expense' => [TransactionType::WITHDRAWAL,],
'income' => [TransactionType::DEPOSIT,],
'deposit' => [TransactionType::DEPOSIT,],
'deposits' => [TransactionType::DEPOSIT,],
'transfer' => [TransactionType::TRANSFER,],
'transfers' => [TransactionType::TRANSFER,],
'opening_balance' => [TransactionType::OPENING_BALANCE,],
'reconciliation' => [TransactionType::RECONCILIATION,],
'reconciliations' => [TransactionType::RECONCILIATION,],
'special' => [TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,],
'specials' => [TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,],
'default' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER,],
];
$return = $types['default'];
if (isset($types[$type])) {
$return = $types[$type];
}
return $return;
}
}

View File

@@ -1,6 +1,6 @@
<?php
/**
* JournalLinkController.php
* TransactionLinkController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
@@ -23,12 +23,14 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\JournalLinkRequest;
use FireflyIII\Api\V1\Requests\TransactionLinkRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionJournalLink;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\JournalLinkTransformer;
use FireflyIII\Transformers\TransactionLinkTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -40,12 +42,12 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class JournalLinkController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* Class TransactionLinkController
*/
class JournalLinkController extends Controller
class TransactionLinkController extends Controller
{
use TransactionFilter;
/** @var JournalRepositoryInterface The journal repository */
private $journalRepository;
/** @var LinkTypeRepositoryInterface The link type repository */
@@ -105,21 +107,25 @@ class JournalLinkController extends Controller
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$linkType = $this->repository->findByName($name);
// get list of accounts. Count it and split it.
// get list of transaction links. Count it and split it.
$collection = $this->repository->getJournalLinks($linkType);
$count = $collection->count();
$journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($journalLinks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.journal_links.index') . $this->buildParams());
$paginator->setPath(route('api.v1.transaction_links.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($journalLinks, new JournalLinkTransformer($this->parameters), 'journal_links');
/** @var TransactionLinkTransformer $transformer */
$transformer = app(TransactionLinkTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($journalLinks, $transformer, 'transaction_links');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -137,14 +143,14 @@ class JournalLinkController extends Controller
public function show(Request $request, TransactionJournalLink $journalLink): JsonResponse
{
$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($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
/** @var TransactionLinkTransformer $transformer */
$transformer = app(TransactionLinkTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($journalLink, $transformer, 'transaction_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -153,19 +159,14 @@ class JournalLinkController extends Controller
/**
* Store new object.
*
* @param JournalLinkRequest $request
* @param TransactionLinkRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(JournalLinkRequest $request): JsonResponse
public function store(TransactionLinkRequest $request): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$data = $request->getAll();
$inward = $this->journalRepository->findNull($data['inward_id'] ?? 0);
$outward = $this->journalRepository->findNull($data['outward_id'] ?? 0);
@@ -175,7 +176,12 @@ class JournalLinkController extends Controller
$data['direction'] = 'inward';
$journalLink = $this->repository->storeLink($data, $inward, $outward);
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
/** @var TransactionLinkTransformer $transformer */
$transformer = app(TransactionLinkTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($journalLink, $transformer, 'transaction_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -184,21 +190,15 @@ class JournalLinkController extends Controller
/**
* Update object.
*
* @param JournalLinkRequest $request
* @param TransactionLinkRequest $request
* @param TransactionJournalLink $journalLink
*
* @return JsonResponse
* @throws FireflyException
*/
public function update(JournalLinkRequest $request, TransactionJournalLink $journalLink): JsonResponse
public function update(TransactionLinkRequest $request, TransactionJournalLink $journalLink): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$manager = new Manager;
$data = $request->getAll();
$data['inward'] = $this->journalRepository->findNull($data['inward_id'] ?? 0);
$data['outward'] = $this->journalRepository->findNull($data['outward_id'] ?? 0);
@@ -208,7 +208,11 @@ class JournalLinkController extends Controller
$data['direction'] = 'inward';
$journalLink = $this->repository->updateLink($journalLink, $data);
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
/** @var TransactionLinkTransformer $transformer */
$transformer = app(TransactionLinkTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($journalLink, $transformer, 'transaction_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -78,7 +78,7 @@ class UserController extends Controller
{
/** @var User $admin */
$admin = auth()->user();
if ($this->repository->hasRole($admin, 'owner')) {
if ($admin->id !== $user->id && $this->repository->hasRole($admin, 'owner')) {
$this->repository->destroy($user);
return response()->json([], 204);
@@ -113,7 +113,11 @@ class UserController extends Controller
$paginator->setPath(route('api.v1.users.index') . $this->buildParams());
// make resource
$resource = new FractalCollection($users, new UserTransformer($this->parameters), 'users');
/** @var UserTransformer $transformer */
$transformer = app(UserTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($users, $transformer, 'users');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -134,12 +138,12 @@ class UserController extends Controller
$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');
/** @var UserTransformer $transformer */
$transformer = app(UserTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($user, $transformer, 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -161,12 +165,13 @@ class UserController extends Controller
$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');
/** @var UserTransformer $transformer */
$transformer = app(UserTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($user, $transformer, 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
@@ -189,12 +194,12 @@ class UserController extends Controller
$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');
/** @var UserTransformer $transformer */
$transformer = app(UserTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($user, $transformer, 'users');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');

View File

@@ -23,6 +23,9 @@
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\IsBoolean;
/**
* Class AccountRequest
*/
@@ -47,10 +50,19 @@ class AccountRequest extends Request
*/
public function getAll(): array
{
$active = true;
$includeNetWorth = true;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}
if (null !== $this->get('include_net_worth')) {
$includeNetWorth = $this->boolean('include_net_worth');
}
$data = [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'include_net_worth' => $this->boolean('include_net_worth'),
'active' => $active,
'include_net_worth' => $includeNetWorth,
'accountType' => $this->string('type'),
'account_type_id' => null,
'currency_id' => $this->integer('currency_id'),
@@ -62,18 +74,13 @@ class AccountRequest extends Request
'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'),
'ccType' => $this->string('credit_card_type'),
'ccMonthlyPaymentDate' => $this->string('monthly_payment_date'),
'notes' => $this->string('notes'),
'interest' => $this->string('interest'),
'interest_period' => $this->string('interest_period'),
];
// new fields for liabilities
// 'liability_type' => $this->string('liability_type'),
// 'liability_start_date' => $this->date('liability_start_date'),
//];
if ('liability' === $data['accountType']) {
$data['openingBalance'] = bcmul($this->string('liability_amount'), '-1');
$data['openingBalanceDate'] = $this->date('liability_start_date');
@@ -95,29 +102,27 @@ class AccountRequest extends Request
$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',
'include_net_worth' => 'required|boolean',
'cc_type' => 'in:' . $ccPaymentTypes . '|required_if:account_role,ccAsset',
'cc_monthly_payment_date' => 'date' . '|required_if:account_role,ccAsset|required_if:cc_type,monthlyFull',
'type' => 'required|in:' . $types,
'notes' => 'min:0|max:65536',
// required fields for liabilities:
'liability_type' => 'required_if:type,liability|in:loan,debt,mortgage,credit card',
'liability_amount' => 'required_if:type,liability|min:0|numeric',
'liability_start_date' => 'required_if:type,liability|date',
'interest' => 'required_if:type,liability|between:0,100|numeric',
'interest_period' => 'required_if:type,liability|in:daily,monthly,yearly',
'name' => 'required|min:1|uniqueAccountForUser',
'type' => 'required|in:' . $types,
'iban' => 'iban|nullable',
'bic' => 'bic|nullable',
'account_number' => 'between:1,255|nullable|uniqueAccountNumberForUser',
'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
'virtual_balance' => 'numeric|nullable',
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'active' => [new IsBoolean],
'include_net_worth' => [new IsBoolean],
'account_role' => 'in:' . $accountRoles . '|required_if:type,asset',
'credit_card_type' => 'in:' . $ccPaymentTypes . '|required_if:account_role,ccAsset',
'monthly_payment_date' => 'date' . '|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull',
'liability_type' => 'required_if:type,liability|in:loan,debt,mortgage',
'liability_amount' => 'required_if:type,liability|min:0|numeric',
'liability_start_date' => 'required_if:type,liability|date',
'interest' => 'required_if:type,liability|between:0,100|numeric',
'interest_period' => 'required_if:type,liability|in:daily,monthly,yearly',
'notes' => 'min:0|max:65536',
];
switch ($this->method()) {
default:

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Bill;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Rules\IsValidAttachmentModel;
@@ -69,9 +70,10 @@ class AttachmentRequest extends Request
{
$models = implode(
',', [
Bill::class,
ImportJob::class,
TransactionJournal::class,
str_replace('FireflyIII\\Models\\', '', Bill::class),
str_replace('FireflyIII\\Models\\', '', ImportJob::class),
str_replace('FireflyIII\\Models\\', '', TransactionJournal::class),
str_replace('FireflyIII\\Models\\', '', Transaction::class),
]
);
$model = $this->string('model');

View File

@@ -50,8 +50,8 @@ class AvailableBudgetRequest extends Request
'currency_id' => $this->integer('currency_id'),
'currency_code' => $this->string('currency_code'),
'amount' => $this->string('amount'),
'start_date' => $this->date('start_date'),
'end_date' => $this->date('end_date'),
'start' => $this->date('start'),
'end' => $this->date('end'),
];
}
@@ -63,11 +63,11 @@ class AvailableBudgetRequest extends Request
public function rules(): array
{
$rules = [
'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',
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'amount' => 'required|numeric|more:0',
'start_date' => 'required|date|before:end_date',
'end_date' => 'required|date|after:start_date',
'start' => 'required|date|before:end',
'end' => 'required|date|after:start',
];
return $rules;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\IsBoolean;
use Illuminate\Validation\Validator;
/**
@@ -50,6 +51,11 @@ class BillRequest extends Request
*/
public function getAll(): array
{
$active = true;
if(null !== $this->get('active')) {
$active = $this->boolean('active');
}
$data = [
'name' => $this->string('name'),
'amount_min' => $this->string('amount_min'),
@@ -59,8 +65,7 @@ class BillRequest extends Request
'date' => $this->date('date'),
'repeat_freq' => $this->string('repeat_freq'),
'skip' => $this->integer('skip'),
'automatch' => $this->boolean('automatch'),
'active' => $this->boolean('active'),
'active' => $active,
'notes' => $this->string('notes'),
];
@@ -78,13 +83,13 @@ class BillRequest extends Request
'name' => 'required|between:1,255|uniqueObjectForUser:bills,name',
'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',
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'date' => 'required|date',
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'required|between:0,31',
'automatch' => 'required|boolean',
'active' => 'required|boolean',
'skip' => 'between:0,31',
'automatch' => [new IsBoolean],
'active' => [new IsBoolean],
'notes' => 'between:1,65536',
];
switch ($this->method()) {

View File

@@ -48,10 +48,12 @@ class BudgetLimitRequest extends Request
public function getAll(): array
{
return [
'budget_id' => $this->integer('budget_id'),
'start_date' => $this->date('start_date'),
'end_date' => $this->date('end_date'),
'amount' => $this->string('amount'),
'budget_id' => $this->integer('budget_id'),
'start' => $this->date('start'),
'end' => $this->date('end'),
'amount' => $this->string('amount'),
'currency_id' => $this->integer('currency_id'),
'currency_code' => $this->string('currency_code'),
];
}
@@ -63,10 +65,12 @@ class BudgetLimitRequest extends Request
public function rules(): array
{
$rules = [
'budget_id' => 'required|exists:budgets,id|belongsToUser:budgets,id',
'start_date' => 'required|before:end_date|date',
'end_date' => 'required|after:start_date|date',
'amount' => 'required|more:0',
'budget_id' => 'required|exists:budgets,id|belongsToUser:budgets,id',
'start' => 'required|before:end|date',
'end' => 'required|after:start|date',
'amount' => 'required|more:0',
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
];
switch ($this->method()) {
default:
@@ -76,6 +80,12 @@ class BudgetLimitRequest extends Request
$rules['budget_id'] = 'required|exists:budgets,id|belongsToUser:budgets,id';
break;
}
// if request has a budget already, drop the rule.
$budget = $this->route()->parameter('budget');
if (null !== $budget) {
unset($rules['budget_id']);
}
return $rules;
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Budget;
use FireflyIII\Rules\IsBoolean;
/**
* Class BudgetRequest
@@ -48,9 +49,14 @@ class BudgetRequest extends Request
*/
public function getAll(): array
{
$active = true;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}
return [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'active' => $active,
'order' => 0,
];
}
@@ -64,7 +70,7 @@ class BudgetRequest extends Request
{
$rules = [
'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name',
'active' => 'required|boolean',
'active' => [new IsBoolean],
];
switch ($this->method()) {
default:

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Category;
use FireflyIII\Rules\IsBoolean;
/**
* Class CategoryRequest
@@ -49,8 +50,7 @@ class CategoryRequest extends Request
public function getAll(): array
{
return [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'name' => $this->string('name')
];
}
@@ -62,8 +62,7 @@ class CategoryRequest extends Request
public function rules(): array
{
$rules = [
'name' => 'required|between:1,100|uniqueObjectForUser:categories,name',
'active' => 'required|boolean',
'name' => 'required|between:1,100|uniqueObjectForUser:categories,name'
];
switch ($this->method()) {
default:

View File

@@ -0,0 +1,83 @@
<?php
/**
* ConfigurationRequest.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\Api\V1\Requests;
use FireflyIII\Rules\IsBoolean;
/**
* Class ConfigurationRequest
*/
class ConfigurationRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
$name = $this->route()->parameter('configName');
switch ($name) {
case 'is_demo_site':
case 'single_user_mode':
return ['value' => $this->boolean('value')];
case 'permission_update_check':
return ['value' => $this->integer('value')];
}
return ['value' => $this->string('value')]; // @codeCoverageIgnore
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
$name = $this->route()->parameter('configName');
switch ($name) {
case 'is_demo_site':
case 'single_user_mode':
return ['value' => ['required', new IsBoolean]];
case 'permission_update_check':
return ['value' => 'required|numeric|between:-1,1'];
}
return ['value' => 'required']; // @codeCoverageIgnore
}
}

View File

@@ -23,6 +23,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\IsBoolean;
/**
* Class CurrencyRequest
@@ -47,12 +49,22 @@ class CurrencyRequest extends Request
*/
public function getAll(): array
{
$enabled = true;
$default = false;
if (null !== $this->get('enabled')) {
$enabled = $this->boolean('enabled');
}
if (null !== $this->get('default')) {
$default = $this->boolean('default');
}
return [
'name' => $this->string('name'),
'code' => $this->string('code'),
'symbol' => $this->string('symbol'),
'decimal_places' => $this->integer('decimal_places'),
'default' => $this->boolean('default'),
'default' => $default,
'enabled' => $enabled,
];
}
@@ -67,8 +79,10 @@ class CurrencyRequest extends Request
'name' => 'required|between:1,255|unique:transaction_currencies,name',
'code' => 'required|between:3,3|unique:transaction_currencies,code',
'symbol' => 'required|between:1,5|unique:transaction_currencies,symbol',
'decimal_places' => 'required|between:0,20|numeric|min:0|max:20',
'default' => 'boolean',
'decimal_places' => 'between:0,20|numeric|min:0|max:20',
'enabled' => [new IsBoolean()],
'default' => [new IsBoolean()],
];
switch ($this->method()) {
@@ -76,7 +90,7 @@ class CurrencyRequest extends Request
break;
case 'PUT':
case 'PATCH':
$currency = $this->route()->parameter('currency');
$currency = $this->route()->parameter('currency_code');
$rules['name'] = 'required|between:1,255|unique:transaction_currencies,name,' . $currency->id;
$rules['code'] = 'required|between:1,255|unique:transaction_currencies,code,' . $currency->id;
$rules['symbol'] = 'required|between:1,255|unique:transaction_currencies,symbol,' . $currency->id;

View File

@@ -58,8 +58,8 @@ class PiggyBankRequest extends Request
'account_id' => $this->integer('account_id'),
'targetamount' => $this->string('target_amount'),
'current_amount' => $current,
'start_date' => $this->date('start_date'),
'target_date' => $this->date('target_date'),
'startdate' => $this->date('start_date'),
'targetdate' => $this->date('target_date'),
'notes' => $this->string('notes'),
];
}

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests;
use Carbon\Carbon;
use FireflyIII\Rules\BelongsUser;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Validation\RecurrenceValidation;
use FireflyIII\Validation\TransactionValidation;
use Illuminate\Validation\Validator;
@@ -54,6 +55,14 @@ class RecurrenceRequest extends Request
*/
public function getAll(): array
{
$active = true;
$applyRules = true;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}
if (null !== $this->get('apply_rules')) {
$applyRules = $this->boolean('apply_rules');
}
$return = [
'recurrence' => [
'type' => $this->string('type'),
@@ -62,8 +71,8 @@ class RecurrenceRequest extends Request
'first_date' => $this->date('first_date'),
'repeat_until' => $this->date('repeat_until'),
'repetitions' => $this->integer('nr_of_repetitions'),
'apply_rules' => $this->boolean('apply_rules'),
'active' => $this->boolean('active'),
'apply_rules' => $applyRules,
'active' => $active,
],
'meta' => [
'piggy_bank_id' => $this->integer('piggy_bank_id'),
@@ -91,19 +100,21 @@ class RecurrenceRequest extends Request
'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title',
'description' => 'between:1,65000',
'first_date' => sprintf('required|date|after:%s', $today->format('Y-m-d')),
'apply_rules' => [new IsBoolean],
'active' => [new IsBoolean],
'repeat_until' => sprintf('date|after:%s', $today->format('Y-m-d')),
'nr_of_repetitions' => 'numeric|between:1,31',
'apply_rules' => 'required|boolean',
'active' => 'required|boolean',
'tags' => 'between:1,64000',
'piggy_bank_id' => 'numeric',
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'required|numeric|between:0,31',
'repetitions.*.weekend' => 'required|numeric|min:1|max:4',
'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.*.description' => 'required|between:1,255',
'transactions.*.amount' => 'required|numeric|more:0',
'transactions.*.foreign_amount' => 'numeric|more:0',
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id',
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'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],
@@ -112,8 +123,8 @@ class RecurrenceRequest extends Request
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.amount' => 'required|numeric|more:0',
'transactions.*.description' => 'required|between:1,255',
];
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Rules\IsBoolean;
/**
@@ -50,10 +51,16 @@ class RuleGroupRequest extends Request
*/
public function getAll(): array
{
$active = true;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}
return [
'title' => $this->string('title'),
'description' => $this->string('description'),
'active' => $this->boolean('active'),
'active' => $active,
];
}
@@ -67,7 +74,7 @@ class RuleGroupRequest extends Request
$rules = [
'title' => 'required|between:1,100|uniqueObjectForUser:rule_groups,title',
'description' => 'between:1,5000|nullable',
'active' => 'required|boolean',
'active' => [new IsBoolean],
];
switch ($this->method()) {
default:

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\IsBoolean;
use Illuminate\Validation\Validator;
@@ -49,17 +50,30 @@ class RuleRequest extends Request
*/
public function getAll(): array
{
$strict = true;
$active = true;
$stopProcessing = false;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}
if (null !== $this->get('strict')) {
$strict = $this->boolean('strict');
}
if (null !== $this->get('stop_processing')) {
$stopProcessing = $this->boolean('stop_processing');
}
$data = [
'title' => $this->string('title'),
'description' => $this->string('description'),
'rule_group_id' => $this->integer('rule_group_id'),
'rule_group_title' => $this->string('rule_group_title'),
'trigger' => $this->string('trigger'),
'strict' => $this->boolean('strict'),
'stop_processing' => $this->boolean('stop_processing'),
'active' => $this->boolean('active'),
'rule_triggers' => $this->getRuleTriggers(),
'rule_actions' => $this->getRuleActions(),
'strict' => $strict,
'stop_processing' => $stopProcessing,
'active' => $active,
'triggers' => $this->getRuleTriggers(),
'actions' => $this->getRuleActions(),
];
return $data;
@@ -75,24 +89,26 @@ class RuleRequest extends Request
$validTriggers = array_keys(config('firefly.rule-triggers'));
$validActions = array_keys(config('firefly.rule-actions'));
// some actions require text:
$contextActions = implode(',', config('firefly.rule-actions-text'));
$rules = [
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
'description' => 'between:1,5000|nullable',
'rule_group_id' => 'required|belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|between:1,255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal',
'rule_triggers.*.name' => 'required|in:' . implode(',', $validTriggers),
'rule_triggers.*.stop_processing' => 'boolean',
'rule_triggers.*.value' => 'required|min:1|ruleTriggerValue',
'rule_actions.*.name' => 'required|in:' . implode(',', $validActions),
'rule_actions.*.value' => 'required_if:rule_actions.*.type,' . $contextActions . '|ruleActionValue',
'rule_actions.*.stop_processing' => 'boolean',
'strict' => 'required|boolean',
'stop_processing' => 'required|boolean',
'active' => 'required|boolean',
// some triggers and actions require text:
$contextTriggers = implode(',', config('firefly.context-rule-triggers'));
$contextActions = implode(',', config('firefly.context-rule-actions'));
$rules = [
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
'description' => 'between:1,5000|nullable',
'rule_group_id' => 'required|belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|between:1,255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal',
'triggers.*.type' => 'required|in:' . implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,' . $contextTriggers . '|min:1|ruleTriggerValue',
'triggers.*.stop_processing' => [new IsBoolean],
'triggers.*.active' => [new IsBoolean],
'actions.*.type' => 'required|in:' . implode(',', $validActions),
'actions.*.value' => 'required_if:actions.*.type,' . $contextActions . '|ruleActionValue',
'actions.*.stop_processing' => [new IsBoolean],
'actions.*.active' => [new IsBoolean],
'strict' => [new IsBoolean],
'stop_processing' => [new IsBoolean],
'active' => [new IsBoolean],
];
return $rules;
@@ -122,10 +138,10 @@ class RuleRequest extends Request
*/
protected function atLeastOneAction(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['rule_actions'] ?? [];
// need at least one transaction
if (0 === \count($repetitions)) {
$data = $validator->getData();
$actions = $data['actions'] ?? [];
// need at least one trigger
if (0 === \count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
}
}
@@ -137,10 +153,10 @@ class RuleRequest extends Request
*/
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['rule_triggers'] ?? [];
// need at least one transaction
if (0 === \count($repetitions)) {
$data = $validator->getData();
$triggers = $data['triggers'] ?? [];
// need at least one trugger
if (0 === \count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
}
}
@@ -150,14 +166,15 @@ class RuleRequest extends Request
*/
private function getRuleActions(): array
{
$actions = $this->get('rule_actions');
$actions = $this->get('actions');
$return = [];
if (\is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'name' => $action['name'],
'type' => $action['type'],
'value' => $action['value'],
'stop_processing' => 1 === (int)($action['stop-processing'] ?? '0'),
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
@@ -170,14 +187,15 @@ class RuleRequest extends Request
*/
private function getRuleTriggers(): array
{
$triggers = $this->get('rule_triggers');
$triggers = $this->get('triggers');
$return = [];
if (\is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'name' => $trigger['name'],
'type' => $trigger['type'],
'value' => $trigger['value'],
'stop_processing' => 1 === (int)($trigger['stop-processing'] ?? '0'),
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
];
}
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* TagRequest.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\Api\V1\Requests;
use FireflyIII\Models\Tag;
/**
* Class TagRequest
*/
class TagRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
$data = [
'tag' => $this->string('tag'),
'date' => $this->date('date'),
'description' => $this->string('description'),
'latitude' => '' === $this->string('latitude') ? null : $this->string('latitude'),
'longitude' => '' === $this->string('longitude') ? null : $this->string('longitude'),
'zoom_level' => $this->integer('zoom_level'),
];
return $data;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
$rules = [
'tag' => 'required|min:1|uniqueObjectForUser:tags,tag',
'description' => 'min:1|nullable',
'date' => 'date|nullable',
'latitude' => 'numeric|min:-90|max:90|nullable|required_with:longitude',
'longitude' => 'numeric|min:-180|max:180|nullable|required_with:latitude',
'zoom_level' => 'numeric|min:0|max:80|nullable',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var Tag $tag */
$tag = $this->route()->parameter('tagOrId');
$rules['tag'] = 'required|min:1|uniqueObjectForUser:tags,tag,' . $tag->id;
break;
}
return $rules;
}
}

View File

@@ -1,6 +1,6 @@
<?php
/**
* JournalLinkRequest.php
* TransactionLinkRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
@@ -29,9 +29,9 @@ use Illuminate\Validation\Validator;
/**
*
* Class JournalLinkRequest
* Class TransactionLinkRequest
*/
class JournalLinkRequest extends Request
class TransactionLinkRequest extends Request
{
/**
* Authorize logged in users.
@@ -71,8 +71,8 @@ class JournalLinkRequest extends Request
return [
'link_type_id' => 'exists:link_types,id|required_without:link_type_name',
'link_type_name' => 'exists:link_types,name|required_without:link_type_id',
'inward_id' => 'required|belongsToUser:transaction_journals,id',
'outward_id' => 'required|belongsToUser:transaction_journals,id',
'inward_id' => 'required|belongsToUser:transaction_journals,id|different:outward_id',
'outward_id' => 'required|belongsToUser:transaction_journals,id|different:inward_id',
'notes' => 'between:0,65000',
];
}
@@ -124,8 +124,12 @@ class JournalLinkRequest extends Request
}
if ($repository->findLink($inward, $outward)) {
$validator->errors()->add('outward_id', 'Already have a link between inward and outward.');
$validator->errors()->add('inward_id', 'Already have a link between inward and outward.');
// only if not updating:
$link = $this->route()->parameter('journalLink');
if (null === $link) {
$validator->errors()->add('outward_id', 'Already have a link between inward and outward.');
$validator->errors()->add('inward_id', 'Already have a link between inward and outward.');
}
}
}
}

View File

@@ -25,6 +25,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\BelongsUser;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsDateOrTime;
use FireflyIII\Validation\TransactionValidation;
use Illuminate\Validation\Validator;
@@ -58,13 +60,22 @@ class TransactionRequest extends Request
{
$data = [
'type' => $this->string('type'),
'date' => $this->date('date'),
'date' => $this->dateTime('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')),
'notes' => $this->string('notes'),
'sepa-cc' => $this->string('sepa_cc'),
'sepa-ct-op' => $this->string('sepa_ct_op'),
'sepa-ct-id' => $this->string('sepa_ct_id'),
'sepa-db' => $this->string('sepa_db'),
'sepa-country' => $this->string('sepa_country'),
'sepa-ep' => $this->string('sepa_ep'),
'sepa-ci' => $this->string('sepa_ci'),
'sepa-batch-id' => $this->string('sepa_batch_id'),
'interest_date' => $this->date('interest_date'),
'book_date' => $this->date('book_date'),
'process_date' => $this->date('process_date'),
@@ -72,8 +83,9 @@ class TransactionRequest extends Request
'payment_date' => $this->date('payment_date'),
'invoice_date' => $this->date('invoice_date'),
'internal_reference' => $this->string('internal_reference'),
'notes' => $this->string('notes'),
'original-source' => sprintf('api-v%s', config('firefly.api_version')),
'bunq_payment_id' => $this->string('bunq_payment_id'),
'external_id' => $this->string('external_id'),
'original-source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
'transactions' => $this->getTransactionData(),
];
@@ -90,9 +102,9 @@ class TransactionRequest extends Request
{
$rules = [
// basic fields for journal:
'type' => 'required|in:withdrawal,deposit,transfer',
'date' => 'required|date',
'type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
'description' => 'between:1,255',
'date' => ['required', new IsDateOrTime],
'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],
@@ -100,6 +112,19 @@ class TransactionRequest extends Request
'tags' => 'between:1,255',
// then, custom fields for journal
'notes' => 'min:1,max:50000|nullable',
// SEPA fields:
'sepa_cc' => 'min:1,max:255|nullable',
'sepa_ct_op' => 'min:1,max:255|nullable',
'sepa_ct_id' => 'min:1,max:255|nullable',
'sepa_db' => 'min:1,max:255|nullable',
'sepa_country' => 'min:1,max:255|nullable',
'sepa_ep' => 'min:1,max:255|nullable',
'sepa_ci' => 'min:1,max:255|nullable',
'sepa_batch_id' => 'min:1,max:255|nullable',
// dates
'interest_date' => 'date|nullable',
'book_date' => 'date|nullable',
'process_date' => 'date|nullable',
@@ -107,13 +132,14 @@ class TransactionRequest extends Request
'payment_date' => 'date|nullable',
'invoice_date' => 'date|nullable',
'internal_reference' => 'min:1,max:255|nullable',
'notes' => 'min:1,max:50000|nullable',
'bunq_payment_id' => 'min:1,max:255|nullable',
'external_id' => 'min:1,max:255|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.*.description' => 'nullable|between:1,255',
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id',
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'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',
@@ -121,8 +147,7 @@ class TransactionRequest extends Request
'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.*.reconciled' => [new IsBoolean],
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
@@ -172,8 +197,8 @@ class TransactionRequest extends Request
$return = [];
foreach ($this->get('transactions') as $index => $transaction) {
$return[] = [
'description' => $transaction['description'] ?? null,
'amount' => $transaction['amount'],
'description' => $transaction['description'] ?? null,
'currency_id' => isset($transaction['currency_id']) ? (int)$transaction['currency_id'] : null,
'currency_code' => $transaction['currency_code'] ?? null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
@@ -187,7 +212,7 @@ class TransactionRequest extends Request
'source_name' => isset($transaction['source_name']) ? (string)$transaction['source_name'] : null,
'destination_id' => isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null,
'destination_name' => isset($transaction['destination_name']) ? (string)$transaction['destination_name'] : null,
'reconciled' => $transaction['reconciled'] ?? false,
'reconciled' => $this->convertBoolean((string)($transaction['reconciled'] ?? 'false')),
'identifier' => $index,
];
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\User;
@@ -64,10 +65,15 @@ class UserRequest extends Request
*/
public function getAll(): array
{
$blocked = false;
if (null === $this->get('blocked')) {
$blocked = $this->boolean('blocked');
}
$data = [
'email' => $this->string('email'),
'blocked' => $this->boolean('blocked'),
'blocked' => $blocked,
'blocked_code' => $this->string('blocked_code'),
'role' => $this->string('role'),
];
return $data;
@@ -82,8 +88,9 @@ class UserRequest extends Request
{
$rules = [
'email' => 'required|email|unique:users,email,',
'blocked' => 'required|boolean',
'blocked' => [new IsBoolean],
'blocked_code' => 'in:email_changed',
'role' => 'in:owner,demo',
];
switch ($this->method()) {
default:

View File

@@ -0,0 +1,415 @@
<?php
/**
* ApplyRules.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\Console\Commands;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\Processor;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
/**
*
* Class ApplyRules
* @codeCoverageIgnore
*/
class ApplyRules extends Command
{
use VerifiesAccessToken;
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will apply your rules and rule groups on a selection of your transactions.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature
= 'firefly:apply-rules
{--user=1 : The user ID that the import should import for.}
{--token= : The user\'s access token.}
{--accounts= : A comma-separated list of asset accounts or liabilities to apply your rules to.}
{--rule_groups= : A comma-separated list of rule groups to apply. Take the ID\'s of these rule groups from the Firefly III interface.}
{--rules= : A comma-separated list of rules to apply. Take the ID\'s of these rules from the Firefly III interface. Using this option overrules the option that selects rule groups.}
{--all_rules : If set, will overrule both settings and simply apply ALL of your rules.}
{--start_date= : The date of the earliest transaction to be included (inclusive). If omitted, will be your very first transaction ever. Format: YYYY-MM-DD}
{--end_date= : The date of the latest transaction to be included (inclusive). If omitted, will be your latest transaction ever. Format: YYYY-MM-DD}';
/** @var Collection */
private $accounts;
/** @var Carbon */
private $endDate;
/** @var Collection */
private $results;
/** @var Collection */
private $ruleGroups;
/** @var Collection */
private $rules;
/** @var Carbon */
private $startDate;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->accounts = new Collection;
$this->rules = new Collection;
$this->ruleGroups = new Collection;
$this->results = new Collection;
}
/**
* Execute the console command.
*
* @return int
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function handle(): int
{
if (!$this->verifyAccessToken()) {
$this->error('Invalid access token.');
return 1;
}
$result = $this->verifyInput();
if (false === $result) {
return 1;
}
// get transactions from asset accounts.
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($this->getUser());
$collector->setAccounts($this->accounts);
$collector->setRange($this->startDate, $this->endDate);
$transactions = $collector->getTransactions();
$count = $transactions->count();
// first run all rule groups:
/** @var RuleGroupRepositoryInterface $ruleGroupRepos */
$ruleGroupRepos = app(RuleGroupRepositoryInterface::class);
$ruleGroupRepos->setUser($this->getUser());
/** @var RuleGroup $ruleGroup */
foreach ($this->ruleGroups as $ruleGroup) {
$this->line(sprintf('Going to apply rule group "%s" to %d transaction(s).', $ruleGroup->title, $count));
$rules = $ruleGroupRepos->getActiveStoreRules($ruleGroup);
$this->applyRuleSelection($rules, $transactions, true);
}
// then run all rules (rule groups should be empty).
if ($this->rules->count() > 0) {
$this->line(sprintf('Will apply %d rule(s) to %d transaction(s)', $this->rules->count(), $transactions->count()));
$this->applyRuleSelection($this->rules, $transactions, false);
}
// filter results:
$this->results = $this->results->unique(
function (Transaction $transaction) {
return (int)$transaction->journal_id;
}
);
$this->line('');
if (0 === $this->results->count()) {
$this->line('The rules were fired but did not influence any transactions.');
}
if ($this->results->count() > 0) {
$this->line(sprintf('The rule(s) was/were fired, and influenced %d transaction(s).', $this->results->count()));
foreach ($this->results as $result) {
$this->line(
vsprintf(
'Transaction #%d: "%s" (%s %s)',
[
$result->journal_id,
$result->description,
$result->transaction_currency_code,
round($result->transaction_amount, $result->transaction_currency_dp),
]
)
);
}
}
return 0;
}
/**
* @param Collection $rules
* @param Collection $transactions
* @param bool $breakProcessing
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
private function applyRuleSelection(Collection $rules, Collection $transactions, bool $breakProcessing): void
{
$bar = $this->output->createProgressBar($rules->count() * $transactions->count());
foreach ($rules as $rule) {
/** @var Processor $processor */
$processor = app(Processor::class);
$processor->make($rule, true);
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
/** @var Rule $rule */
$bar->advance();
$result = $processor->handleTransaction($transaction);
if (true === $result) {
$this->results->push($transaction);
}
}
if (true === $rule->stop_processing && true === $breakProcessing) {
$this->line('');
$this->line(sprintf('Rule #%d ("%s") says to stop processing.', $rule->id, $rule->title));
return;
}
}
$this->line('');
}
/**
*
*/
private function grabAllRules(): void
{
if (true === $this->option('all_rules')) {
/** @var RuleRepositoryInterface $ruleRepos */
$ruleRepos = app(RuleRepositoryInterface::class);
$ruleRepos->setUser($this->getUser());
$this->rules = $ruleRepos->getAll();
// reset rule groups.
$this->ruleGroups = new Collection;
}
}
/**
*
*/
private function parseDates(): void
{
// parse start date.
$startDate = Carbon::create()->startOfMonth();
$startString = $this->option('start_date');
if (null === $startString) {
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($this->getUser());
$first = $repository->firstNull();
if (null !== $first) {
$startDate = $first->date;
}
}
if (null !== $startString && '' !== $startString) {
$startDate = Carbon::createFromFormat('Y-m-d', $startString);
}
// parse end date
$endDate = Carbon::now();
$endString = $this->option('end_date');
if (null !== $endString && '' !== $endString) {
$endDate = Carbon::createFromFormat('Y-m-d', $endString);
}
if ($startDate > $endDate) {
[$endDate, $startDate] = [$startDate, $endDate];
}
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/**
* @return bool
* @throws \FireflyIII\Exceptions\FireflyException
*/
private function verifyInput(): bool
{
// verify account.
$result = $this->verifyInputAccounts();
if (false === $result) {
return $result;
}
// verify rule groups.
$result = $this->verifyRuleGroups();
if (false === $result) {
return $result;
}
// verify rules.
$result = $this->verifyRules();
if (false === $result) {
return $result;
}
$this->grabAllRules();
$this->parseDates();
//$this->line('Number of rules found: ' . $this->rules->count());
$this->line('Start date is ' . $this->startDate->format('Y-m-d'));
$this->line('End date is ' . $this->endDate->format('Y-m-d'));
return true;
}
/**
* @return bool
* @throws \FireflyIII\Exceptions\FireflyException
*/
private function verifyInputAccounts(): bool
{
$accountString = $this->option('accounts');
if (null === $accountString || '' === $accountString) {
$this->error('Please use the --accounts to indicate the accounts to apply rules to.');
return false;
}
$finalList = new Collection;
$accountList = explode(',', $accountString);
if (0 === \count($accountList)) {
$this->error('Please use the --accounts to indicate the accounts to apply rules to.');
return false;
}
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountRepository->setUser($this->getUser());
foreach ($accountList as $accountId) {
$accountId = (int)$accountId;
$account = $accountRepository->findNull($accountId);
if (null !== $account
&& \in_array(
$account->accountType->type, [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE], true
)) {
$finalList->push($account);
}
}
if (0 === $finalList->count()) {
$this->error('Please make sure all accounts in --accounts are asset accounts or liabilities.');
return false;
}
$this->accounts = $finalList;
return true;
}
/**
* @return bool
* @throws \FireflyIII\Exceptions\FireflyException
*/
private function verifyRuleGroups(): bool
{
$ruleGroupString = $this->option('rule_groups');
if (null === $ruleGroupString || '' === $ruleGroupString) {
// can be empty.
return true;
}
$ruleGroupList = explode(',', $ruleGroupString);
if (0 === \count($ruleGroupList)) {
// can be empty.
return true;
}
/** @var RuleGroupRepositoryInterface $ruleGroupRepos */
$ruleGroupRepos = app(RuleGroupRepositoryInterface::class);
$ruleGroupRepos->setUser($this->getUser());
foreach ($ruleGroupList as $ruleGroupId) {
$ruleGroupId = (int)$ruleGroupId;
$ruleGroup = $ruleGroupRepos->find($ruleGroupId);
$this->ruleGroups->push($ruleGroup);
}
return true;
}
/**
* @return bool
* @throws \FireflyIII\Exceptions\FireflyException
*/
private function verifyRules(): bool
{
$ruleString = $this->option('rules');
if (null === $ruleString || '' === $ruleString) {
// can be empty.
return true;
}
$finalList = new Collection;
$ruleList = explode(',', $ruleString);
if (0 === \count($ruleList)) {
// can be empty.
return true;
}
/** @var RuleRepositoryInterface $ruleRepos */
$ruleRepos = app(RuleRepositoryInterface::class);
$ruleRepos->setUser($this->getUser());
foreach ($ruleList as $ruleId) {
$ruleId = (int)$ruleId;
$rule = $ruleRepos->find($ruleId);
if (null !== $rule) {
$finalList->push($rule);
}
}
if ($finalList->count() > 0) {
// reset rule groups.
$this->ruleGroups = new Collection;
$this->rules = $finalList;
}
return true;
}
}

View File

@@ -33,7 +33,7 @@ use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Console\Command;
use Storage;
use Illuminate\Support\Facades\Storage;
/**
* Class CreateExport.
@@ -136,10 +136,14 @@ class CreateExport extends Command
$processor->createZipFile();
$disk = Storage::disk('export');
$fileName = sprintf('export-%s.zip', date('Y-m-d_H-i-s'));
$disk->move($job->key . '.zip', $fileName);
$localPath = storage_path('export') . '/' . $job->key . '.zip';
$this->line('The export has finished! You can find the ZIP file in this location:');
$this->line(storage_path(sprintf('export/%s', $fileName)));
// "move" from local to export disk
$disk->put($fileName, file_get_contents($localPath));
unlink($localPath);
$this->line('The export has finished! You can find the ZIP file in export disk with file name:');
$this->line($fileName);
return 0;
}

View File

@@ -1,5 +1,27 @@
<?php
/**
* Cron.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\Console\Commands;
use FireflyIII\Exceptions\FireflyException;

View File

@@ -0,0 +1,138 @@
<?php
/**
* DecryptDatabase.php
* Copyright (c) 2019 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\Console\Commands;
use Crypt;
use DB;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException;
use Log;
/**
*
* Class DecryptDatabase
*/
class DecryptDatabase extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Decrypts the database.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:decrypt-all';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->line('Going to decrypt the database.');
$tables = [
'accounts' => ['name', 'iban'],
'attachments' => ['filename', 'mime', 'title', 'description'],
'bills' => ['name', 'match'],
'budgets' => ['name'],
'categories' => ['name'],
'piggy_banks' => ['name'],
'preferences' => ['data'],
'tags' => ['tag', 'description'],
'transaction_journals' => ['description'],
'transactions' => ['description'],
'journal_links' => ['comment'],
];
foreach ($tables as $table => $fields) {
if ($this->isDecrypted($table)) {
$this->info(sprintf('No decryption required for table "%s".', $table));
continue;
}
foreach ($fields as $field) {
$rows = DB::table($table)->get(['id', $field]);
foreach ($rows as $row) {
$original = $row->$field;
if (null === $original) {
continue;
}
$id = $row->id;
$value = $this->tryDecrypt($original);
if ($value !== $original) {
Log::debug(sprintf('Decrypted field "%s" "%s" to "%s" in table "%s" (row #%d)', $field, $original, $value, $table, $id));
DB::table($table)->where('id', $id)->update([$field => $value]);
}
}
}
$this->line(sprintf('Decrypted the data in table "%s".', $table));
// mark as decrypted:
$configName = sprintf('is_decrypted_%s', $table);
FireflyConfig::set($configName, true);
}
$this->info('Done!');
return 0;
}
/**
* @param string $table
*
* @return bool
*/
private function isDecrypted(string $table): bool
{
$configName = sprintf('is_decrypted_%s', $table);
$configVar = FireflyConfig::get($configName, false);
if (null !== $configVar) {
return $configVar->data;
}
return false;
}
/**
* @param $value
*
* @return mixed
*/
private function tryDecrypt($value)
{
try {
$value = Crypt::decrypt($value);
} catch (DecryptException $e) {
//Log::debug(sprintf('Could not decrypt. %s', $e->getMessage()));
}
return $value;
}
}

View File

@@ -39,7 +39,7 @@ class EncryptFile extends Command
*
* @var string
*/
protected $description = 'Encrypts a file and places it in the storage/upload directory.';
protected $description = 'Encrypts a file and places it in the upload disk.';
/**
* The name and signature of the console command.

View File

@@ -1,94 +0,0 @@
<?php
/**
* UseEncryption.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\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
/**
* Class UseEncryption.
* @codeCoverageIgnore
*/
class UseEncryption extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will make sure that entries in the database will be encrypted (or not) according to the settings in .env';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:use-encryption';
/**
* Execute the console command.
*/
public function handle(): int
{
if (true === config('firefly.encryption')) {
$this->info('Firefly III configuration calls for encrypted data.');
}
if (false === config('firefly.encryption')) {
$this->info('Firefly III configuration calls for unencrypted data.');
}
$this->handleObjects('Account', 'name', 'encrypted');
$this->handleObjects('Bill', 'name', 'name_encrypted');
$this->handleObjects('Bill', 'match', 'match_encrypted');
$this->handleObjects('Budget', 'name', 'encrypted');
$this->handleObjects('Category', 'name', 'encrypted');
$this->handleObjects('PiggyBank', 'name', 'encrypted');
$this->handleObjects('TransactionJournal', 'description', 'encrypted');
return 0;
}
/**
* Run each object and encrypt them (or not).
*
* @param string $class
* @param string $field
* @param string $indicator
*/
public function handleObjects(string $class, string $field, string $indicator): void
{
$fqn = sprintf('FireflyIII\Models\%s', $class);
$encrypt = true === config('firefly.encryption') ? 0 : 1;
/** @noinspection PhpUndefinedMethodInspection */
$set = $fqn::where($indicator, $encrypt)->get();
foreach ($set as $entry) {
$newName = $entry->$field;
$entry->$field = $newName;
/** @noinspection PhpUndefinedMethodInspection */
$entry->save();
}
/** @noinspection PhpUndefinedMethodInspection */
$this->line(sprintf('Updated %d %s.', $set->count(), strtolower(Str::plural($class))));
}
}

View File

@@ -23,17 +23,37 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Log;
/**
* Trait VerifiesAccessToken.
*
* Verifies user access token for sensitive commands.
*
* @codeCoverageIgnore
*/
trait VerifiesAccessToken
{
/**
* @return User
* @throws FireflyException
*/
public function getUser(): User
{
$userId = (int)$this->option('user');
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
$user = $repository->findNull($userId);
if (null === $user) {
throw new FireflyException('User is unexpectedly NULL');
}
return $user;
}
/**
* Abstract method to make sure trait knows about method "option".
*

View File

@@ -28,12 +28,15 @@ namespace FireflyIII\Console\Commands;
use Crypt;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\Category;
use FireflyIII\Models\LinkType;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\User\UserRepositoryInterface;
@@ -41,6 +44,7 @@ use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Log;
use Schema;
use stdClass;
@@ -95,6 +99,7 @@ class VerifyDatabase extends Command
$this->fixDoubleAmounts();
$this->fixBadMeta();
$this->removeBills();
$this->enableCurrencies();
return 0;
}
@@ -150,6 +155,45 @@ class VerifyDatabase extends Command
}
}
/**
* Will make sure that all currencies in use are actually enabled.
*/
private function enableCurrencies(): void
{
$found = [];
// get all meta entries
/** @var Collection $meta */
$meta = AccountMeta::where('name', 'currency_id')->groupBy('data')->get(['data']);
foreach ($meta as $entry) {
$found[] = (int)$entry->data;
}
// get all from journals:
/** @var Collection $journals */
$journals = TransactionJournal::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
foreach ($journals as $entry) {
$found[] = (int)$entry->transaction_currency_id;
}
// get all from transactions
/** @var Collection $transactions */
$transactions = Transaction::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
foreach ($transactions as $entry) {
$found[] = (int)$entry->transaction_currency_id;
}
// get all from budget limits
/** @var Collection $limits */
$limits = BudgetLimit::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
foreach ($limits as $entry) {
$found[] = (int)$entry->transaction_currency_id;
}
$found = array_unique($found);
TransactionCurrency::whereIn('id', $found)->update(['enabled' => true]);
}
/**
* Fix the situation where the matching transactions of a journal somehow have non-matching categories or budgets.
*
@@ -406,12 +450,6 @@ class VerifyDatabase extends Command
/** @var stdClass $entry */
foreach ($set as $entry) {
$objName = $entry->name;
try {
$objName = Crypt::decrypt($objName);
} catch (DecryptException $e) {
// it probably was not encrypted.
Log::debug(sprintf('Not a problem: %s', $e->getMessage()));
}
// also count the transactions:
$countTransactions = DB::table('budget_transaction')->where('budget_id', $entry->id)->count();
@@ -444,12 +482,6 @@ class VerifyDatabase extends Command
/** @var stdClass $entry */
foreach ($set as $entry) {
$objName = $entry->name;
try {
$objName = Crypt::decrypt($objName);
} catch (DecryptException $e) {
// it probably was not encrypted.
Log::debug(sprintf('Not a problem: %s', $e->getMessage()));
}
// also count the transactions:
$countTransactions = DB::table('category_transaction')->where('category_id', $entry->id)->count();
@@ -583,12 +615,6 @@ class VerifyDatabase extends Command
/** @var stdClass $entry */
foreach ($set as $entry) {
$objName = $entry->name;
try {
$objName = Crypt::decrypt($objName);
} catch (DecryptException $e) {
// it probably was not encrypted.
Log::debug(sprintf('Not a problem: %s', $e->getMessage()));
}
$line = sprintf(
'User #%d (%s) has %s #%d ("%s") which has no transactions.',

View File

@@ -1,4 +1,25 @@
<?php
/**
* RequestedReportOnJournals.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
/**
* RequestedReportOnJournals.php

View File

@@ -38,18 +38,14 @@ class StoredTransactionJournal extends Event
/** @var TransactionJournal The journal that was stored. */
public $journal;
/** @var int The piggy bank ID. */
public $piggyBankId;
/**
* Create a new event instance.
*
* @param TransactionJournal $journal
* @param int $piggyBankId
*/
public function __construct(TransactionJournal $journal, int $piggyBankId)
public function __construct(TransactionJournal $journal)
{
$this->journal = $journal;
$this->piggyBankId = $piggyBankId;
}
}

View File

@@ -38,6 +38,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Handler
*
* @codeCoverageIgnore
*/
class Handler extends ExceptionHandler
@@ -92,7 +93,7 @@ class Handler extends ExceptionHandler
}
if ($exception instanceof FireflyException || $exception instanceof ErrorException || $exception instanceof OAuthServerException) {
$isDebug = env('APP_DEBUG', false);
$isDebug = config('app.debug');
return response()->view('errors.FireflyException', ['exception' => $exception, 'debug' => $isDebug], 500);
}
@@ -116,11 +117,11 @@ class Handler extends ExceptionHandler
public function report(Exception $exception)
{
$doMailError = env('SEND_ERROR_MESSAGE', true);
$doMailError = config('firefly.send_error_message');
// if the user wants us to mail:
if (true === $doMailError
// and if is one of these error instances
&& ($exception instanceof FireflyException || $exception instanceof ErrorException || $exception instanceof OAuthServerException)) {
&& ($exception instanceof FireflyException || $exception instanceof ErrorException)) {
$userData = [
'id' => 0,
'email' => 'unknown@example.com',
@@ -145,7 +146,7 @@ class Handler extends ExceptionHandler
// create job that will mail.
$ipAddress = Request::ip() ?? '0.0.0.0';
$job = new MailError($userData, env('SITE_OWNER', ''), $ipAddress, $data);
$job = new MailError($userData, (string)config('firefly.site_owner'), $ipAddress, $data);
dispatch($job);
}

View File

@@ -148,14 +148,14 @@ final class Entry
$entry->transaction_type = $transaction->transaction_type_type;
$entry->asset_account_id = (string)$transaction->account_id;
$entry->asset_account_name = app('steam')->tryDecrypt($transaction->account_name);
$entry->asset_account_name = $transaction->account_name;
$entry->asset_account_iban = $transaction->account_iban;
$entry->asset_account_number = $transaction->account_number;
$entry->asset_account_bic = $transaction->account_bic;
$entry->asset_currency_code = $transaction->account_currency_code;
$entry->opposing_account_id = (string)$transaction->opposing_account_id;
$entry->opposing_account_name = app('steam')->tryDecrypt($transaction->opposing_account_name);
$entry->opposing_account_name = $transaction->opposing_account_name;
$entry->opposing_account_iban = $transaction->opposing_account_iban;
$entry->opposing_account_number = $transaction->opposing_account_number;
$entry->opposing_account_bic = $transaction->opposing_account_bic;
@@ -163,23 +163,23 @@ final class Entry
// budget
$entry->budget_id = (string)$transaction->transaction_budget_id;
$entry->budget_name = app('steam')->tryDecrypt($transaction->transaction_budget_name);
$entry->budget_name = $transaction->transaction_budget_name;
if (null === $transaction->transaction_budget_id) {
$entry->budget_id = $transaction->transaction_journal_budget_id;
$entry->budget_name = app('steam')->tryDecrypt($transaction->transaction_journal_budget_name);
$entry->budget_name = $transaction->transaction_journal_budget_name;
}
// category
$entry->category_id = (string)$transaction->transaction_category_id;
$entry->category_name = app('steam')->tryDecrypt($transaction->transaction_category_name);
$entry->category_name = $transaction->transaction_category_name;
if (null === $transaction->transaction_category_id) {
$entry->category_id = $transaction->transaction_journal_category_id;
$entry->category_name = app('steam')->tryDecrypt($transaction->transaction_journal_category_name);
$entry->category_name = $transaction->transaction_journal_category_name;
}
// budget
$entry->bill_id = (string)$transaction->bill_id;
$entry->bill_name = app('steam')->tryDecrypt($transaction->bill_name);
$entry->bill_name = $transaction->bill_name;
$entry->tags = $transaction->tags;
$entry->notes = $transaction->notes;

View File

@@ -42,7 +42,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
use Storage;
use Illuminate\Support\Facades\Storage;
use ZipArchive;
/**
@@ -184,7 +184,7 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Create a ZIP file.
* Create a ZIP file locally (!) in storage_path('export').
*
* @return bool
*
@@ -195,9 +195,9 @@ class ExpandedProcessor implements ProcessorInterface
{
$zip = new ZipArchive;
$file = $this->job->key . '.zip';
$fullPath = storage_path('export') . '/' . $file;
$localPath = storage_path('export') . '/' . $file;
if (true !== $zip->open($fullPath, ZipArchive::CREATE)) {
if (true !== $zip->open($localPath, ZipArchive::CREATE)) {
throw new FireflyException('Cannot store zip file.');
}
// for each file in the collection, add it to the zip file.
@@ -368,7 +368,7 @@ class ExpandedProcessor implements ProcessorInterface
foreach ($set as $entry) {
$id = (int)$entry->transaction_journal_id;
$result[$id] = $result[$id] ?? [];
$result[$id][] = Crypt::decrypt($entry->tag);
$result[$id][] = $entry->tag;
}
return $result;

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Export\Exporter;
use FireflyIII\Export\Entry\Entry;
use League\Csv\Writer;
use Storage;
use Illuminate\Support\Facades\Storage;
/**
* Class CsvExporter.
@@ -57,15 +57,11 @@ class CsvExporter extends BasicExporter implements ExporterInterface
*/
public function run(): bool
{
// create temporary file:
$this->tempFile();
// necessary for CSV writer:
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->fileName;
// choose file name:
$this->fileName = $this->job->key . '-records.csv';
//we create the CSV into memory
$writer = Writer::createFromPath($fullPath);
$writer = Writer::createFromString('');
$rows = [];
// get field names for header row:
@@ -86,18 +82,9 @@ class CsvExporter extends BasicExporter implements ExporterInterface
$rows[] = $line;
}
$writer->insertAll($rows);
$disk = Storage::disk('export');
$disk->put($this->fileName, $writer->getContent());
return true;
}
/**
* Make a temp file.
*/
private function tempFile()
{
$this->fileName = $this->job->key . '-records.csv';
// touch file in export directory:
$disk = Storage::disk('export');
$disk->put($this->fileName, '');
}
}

View File

@@ -30,6 +30,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Services\Internal\Support\AccountServiceTrait;
use FireflyIII\User;
use Log;
@@ -47,11 +48,12 @@ class AccountFactory
use AccountServiceTrait;
/**
* Constructor.
* AccountFactory constructor.
* @codeCoverageIgnore
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
@@ -79,7 +81,6 @@ class AccountFactory
// account may exist already:
$return = $this->find($data['name'], $type->type);
if (null === $return) {
// create it:
$databaseData
@@ -92,6 +93,21 @@ class AccountFactory
'iban' => $data['iban'],
];
// find currency, or use default currency instead.
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
/** @var TransactionCurrency $currency */
$currency = $factory->find((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null));
if (null === $currency) {
// use default currency:
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
}
$currency->enabled =true;
$currency->save();
unset($data['currency_code']);
$data['currency_id'] = $currency->id;
// remove virtual balance when not an asset account or a liability
$canHaveVirtual = [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD];
if (!\in_array($type->type, $canHaveVirtual, true)) {

View File

@@ -39,7 +39,7 @@ class AccountMetaFactory
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}

View File

@@ -23,8 +23,11 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\User;
use Log;
@@ -33,31 +36,46 @@ use Log;
*/
class AttachmentFactory
{
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
/** @var User */
private $user;
/**
* @param array $data
*
* @return Attachment|null
* @throws FireflyException
*/
public function create(array $data): ?Attachment
{
// append if necessary.
$model = false === strpos('FireflyIII', $data['model']) ? 'FireflyIII\\Models\\' . $data['model'] : $data['model'];
if (Transaction::class === $model) {
/** @var Transaction $transaction */
$transaction = $this->user->transactions()->find((int)$data['model_id']);
if (null === $transaction) {
throw new FireflyException('Unexpectedly could not find transaction');
}
$data['model_id'] = $transaction->transaction_journal_id;
$model = TransactionJournal::class;
}
// create attachment:
$attachment = Attachment::create(
[
'user_id' => $this->user->id,
'attachable_id' => $data['model_id'],
'attachable_type' => $data['model'],
'attachable_type' => $model,
'md5' => '',
'filename' => $data['filename'],
'title' => '' === $data['title'] ? null : $data['title'],

View File

@@ -36,17 +36,18 @@ use Log;
*/
class BillFactory
{
use BillServiceTrait;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}
use BillServiceTrait;
/** @var User */
private $user;
@@ -60,7 +61,13 @@ class BillFactory
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
/** @var TransactionCurrency $currency */
$currency = $factory->find((int)$data['currency_id'], (string)$data['currency_code']);
$currency = $factory->find((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null));
if(null === $currency) {
// use default currency:
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
}
/** @var Bill $bill */
$bill = Bill::create(
[
@@ -73,7 +80,7 @@ class BillFactory
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
'skip' => $data['skip'],
'automatch' => $data['automatch'] ?? true,
'automatch' => true,
'active' => $data['active'] ?? true,
]
);

View File

@@ -39,7 +39,7 @@ class BudgetFactory
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}

View File

@@ -39,7 +39,7 @@ class CategoryFactory
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}

View File

@@ -42,7 +42,7 @@ class PiggyBankEventFactory
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}

View File

@@ -38,7 +38,7 @@ class PiggyBankFactory
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}

View File

@@ -44,7 +44,7 @@ class RecurrenceFactory
*/
public function __construct()
{
if ('testing' === env('APP_ENV')) {
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
}
}

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