Compare commits

...

171 Commits

Author SHA1 Message Date
James Cole
34f16dcdd5 Merge branch 'release/v6.0.12' 2023-06-11 16:34:30 +02:00
James Cole
f18aae39b8 chore: Meta files for new release 2023-06-11 16:34:06 +02:00
James Cole
924171e7b9 Merge pull request #7640 from firefly-iii/fix-7613
Fix #7613
2023-06-11 16:15:40 +02:00
James Cole
6b580212bf Fix #7613 2023-06-11 16:15:22 +02:00
James Cole
208ae1cae7 Merge pull request #7639 from firefly-iii/fix-7619
Fix #7619
2023-06-11 16:12:41 +02:00
James Cole
3aa7fe47de Fix #7619 2023-06-11 16:12:13 +02:00
James Cole
5318082467 Merge pull request #7638 from firefly-iii/chore2
Fix CSS again
2023-06-11 15:51:42 +02:00
James Cole
941ec095e5 Fix CSS again 2023-06-11 15:51:17 +02:00
James Cole
d5ebd8e57c Merge pull request #7637 from firefly-iii/chore
Chore: Update version and better colors.
2023-06-11 12:21:11 +02:00
James Cole
ebe087984d Chore: Update version and better colors. 2023-06-11 12:20:57 +02:00
James Cole
fa993e02dd Merge pull request #7634 from firefly-iii/fix-missing-var
Fix: missing variable
2023-06-10 21:42:09 +02:00
James Cole
44df77f45a Fix: missing variable 2023-06-10 21:41:45 +02:00
James Cole
0f8f95de9a Merge pull request #7628 from firefly-iii/fix-7618
Fix 7618
2023-06-10 16:21:40 +02:00
James Cole
f32283d2f1 Fix #7618 2023-06-10 16:21:01 +02:00
James Cole
14f8695599 Merge pull request #7627 from firefly-iii/fix-forms
Fix forms
2023-06-10 16:09:00 +02:00
James Cole
f8b48f7455 Fix forms 2023-06-10 16:08:32 +02:00
James Cole
70e2aab073 Merge pull request #7623 from firefly-iii/fix-7620
Fix #7620
2023-06-10 13:15:33 +02:00
James Cole
12db745f17 Fix #7620 2023-06-10 13:15:06 +02:00
James Cole
8a48cc690f Merge pull request #7612 from firefly-iii/logo-tune-2
Another small tune
2023-06-06 12:42:44 +02:00
James Cole
eb313c65a5 Another small tune 2023-06-06 12:42:20 +02:00
James Cole
07d6cbc194 Merge pull request #7611 from firefly-iii/logo-tune
chore: tune the logo
2023-06-06 12:38:50 +02:00
James Cole
8975a462c4 Merge pull request #7610 from firefly-iii/fix-form
fix: expand form elements with ID
2023-06-06 06:19:42 +02:00
James Cole
2e4f07d058 fix: expand form elements with ID 2023-06-06 06:19:24 +02:00
James Cole
74a2935fea Merge pull request #7600 from firefly-iii/upgrade-html
Upgrade html
2023-06-04 15:16:47 +02:00
James Cole
3d02468828 fix: replace deprecated package 2023-06-04 15:16:17 +02:00
James Cole
0438fb5a2e fix: remove and replace old form functions 2023-06-04 10:09:45 +02:00
James Cole
a4f9a6fd42 fix: replace deprecated form.model with html 2023-06-04 10:09:24 +02:00
James Cole
a0be4c9daa chore: tune the logo 2023-06-04 07:53:56 +02:00
James Cole
2dc003bd85 Merge pull request #7597 from firefly-iii/logo-expansion
feat: Expand logo in startup scripts
2023-06-04 06:58:52 +02:00
James Cole
78aa8bd838 feat: Expand logo in startup scripts 2023-06-04 06:58:35 +02:00
James Cole
f55fde2b52 Merge pull request #7596 from firefly-iii/fix-yaml
fix qodana yaml
2023-06-04 06:33:21 +02:00
James Cole
232572549e fix qodana yaml 2023-06-04 06:33:05 +02:00
James Cole
d07705c329 Merge pull request #7595 from firefly-iii/qodana-fix
chore: fix various qodana issues
2023-06-04 06:30:45 +02:00
James Cole
688ca8e374 chore: fix various qodana issues 2023-06-04 06:30:22 +02:00
James Cole
160c364d2a Merge pull request #7594 from firefly-iii/missing-bracket
fix: extra bracket breaks code.
2023-06-04 06:14:38 +02:00
James Cole
2b3e6bfbb9 Merge pull request #7593 from josephbadow/fix-urls-envexample-#7580
Fix URLs in .env.example #7580
2023-06-04 06:13:49 +02:00
James Cole
5a55d1db24 fix: extra bracket breaks code. 2023-06-04 06:13:24 +02:00
josephbadow
bd252dbc16 amend links in .env.example to point to correct documentation pages 2023-06-03 22:16:59 +02:00
James Cole
30124855e3 Merge pull request #7592 from firefly-iii/fix-7589
First attempt to fix #7589
2023-06-03 21:20:15 +02:00
James Cole
463ebd296f First attempt to fix #7589 2023-06-03 21:17:49 +02:00
James Cole
2e7a17560d Merge branch 'main' into develop 2023-06-03 17:19:14 +02:00
James Cole
374d5a074d Merge pull request #7591 from firefly-iii/fix-command-output
chore: fix command output
2023-06-03 17:18:21 +02:00
James Cole
88b294d873 chore: fix command output 2023-06-03 17:18:04 +02:00
James Cole
0aa6d5b322 Merge pull request #7590 from firefly-iii/fix-7588
Fix https://github.com/firefly-iii/firefly-iii/issues/7588
2023-06-03 17:16:51 +02:00
James Cole
1357074dcd Fix https://github.com/firefly-iii/firefly-iii/issues/7588 2023-06-03 17:16:28 +02:00
James Cole
4a03847c14 Merge pull request #7584 from firefly-iii/JC5-patch-1
Create sonarcloud.yml
2023-06-03 05:53:03 +02:00
James Cole
346289fdb2 Create sonarcloud.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-06-03 05:52:50 +02:00
James Cole
673c7d98f6 Merge pull request #7583 from firefly-iii/JC5-patch-1
Delete sonarcloud.yaml
2023-06-03 05:52:26 +02:00
James Cole
9473fb849a Delete sonarcloud.yaml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-06-03 05:52:17 +02:00
James Cole
f60e244739 Merge pull request #7579 from firefly-iii/JC5-patch-1
Update contributing.md
2023-06-02 12:30:58 +02:00
James Cole
a571106f0f Update contributing.md
Signed-off-by: James Cole <james@firefly-iii.org>
2023-06-02 12:30:41 +02:00
James Cole
244d9be46e Merge pull request #7578 from firefly-iii/improv-commands
cleanup: Commands are a lot less verbal and report better on success …
2023-06-02 07:36:53 +02:00
James Cole
dcf71c6fdf cleanup: Commands are a lot less verbal and report better on success / failue 2023-06-02 07:36:17 +02:00
James Cole
1e1497ff4e Merge pull request #7577 from firefly-iii/fix-billrepos
clean: remove deprecated methods and refactor as necessary.
2023-06-02 06:38:49 +02:00
James Cole
b72aa92e55 clean: remove deprecated methods and refactor as necessary. 2023-06-02 06:38:07 +02:00
James Cole
527f18c1e3 Merge branch 'main' into develop 2023-06-01 19:50:19 +02:00
James Cole
788003dcdc Merge pull request #7574 from firefly-iii/fix-7572
Fix #7572
2023-06-01 19:50:05 +02:00
James Cole
c764ddd3be Fix #7572 2023-06-01 19:49:28 +02:00
James Cole
057ac0691c Update closed-issues.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-06-01 06:43:28 +02:00
James Cole
4334e9bed7 chore: small fixes and prep for new language 2023-05-30 20:15:07 +02:00
James Cole
a9bb87b0c6 Merge pull request #7566 from firefly-iii/chore/fix-small-issues
chore: fix various small sonacloud issues to see if the actions run c…
2023-05-29 14:18:50 +02:00
James Cole
43f668dc65 config: no more sonarcloud / qodana for each PR. 2023-05-29 14:18:43 +02:00
James Cole
6ed5892cf9 chore: fix various small sonacloud issues to see if the actions run correctly. 2023-05-29 14:17:10 +02:00
James Cole
023a3fdade Merge pull request #7565 from firefly-iii/chore/cleanup
chore: code cleanup.
2023-05-29 14:01:32 +02:00
James Cole
1b52147a05 chore: code cleanup. 2023-05-29 13:56:55 +02:00
James Cole
7f7644c92f Merge pull request #7564 from firefly-iii/fix-ci
Fix ci
2023-05-29 12:06:09 +02:00
James Cole
70b756baaf Fix linter 2023-05-29 12:05:45 +02:00
James Cole
0f008b9b1e Merge branch 'main' into develop 2023-05-29 11:58:39 +02:00
James Cole
4d956858de Merge pull request #7563 from firefly-iii/dependabot/npm_and_yarn/develop/postcss-8.4.24 2023-05-29 06:01:06 +02:00
James Cole
959370a204 Merge pull request #7562 from firefly-iii/dependabot/composer/develop/symfony/http-client-6.2.11 2023-05-29 06:00:58 +02:00
dependabot[bot]
336829cd24 Bump postcss from 8.4.23 to 8.4.24
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.23 to 8.4.24.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.23...8.4.24)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 03:57:03 +00:00
dependabot[bot]
5975ab5170 Bump symfony/http-client from 6.2.10 to 6.2.11
Bumps [symfony/http-client](https://github.com/symfony/http-client) from 6.2.10 to 6.2.11.
- [Release notes](https://github.com/symfony/http-client/releases)
- [Changelog](https://github.com/symfony/http-client/blob/6.3/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-client/compare/v6.2.10...v6.2.11)

---
updated-dependencies:
- dependency-name: symfony/http-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 03:56:29 +00:00
James Cole
eba0e942e8 Update sonarcloud.yaml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 16:08:47 +02:00
James Cole
f45c20db1e Update cleanup.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 16:08:34 +02:00
James Cole
79afe09d8d Update cleanup.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 16:07:47 +02:00
James Cole
334d010a24 Create sonarcloud.yaml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 16:07:08 +02:00
James Cole
91947daa5b Create sonar-project.properties
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 16:05:25 +02:00
James Cole
aad2ca4488 Update qodana.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 15:58:48 +02:00
James Cole
7c68a96f7b Update qodana.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 15:56:35 +02:00
James Cole
2e1e8b5d39 Update qodana.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 15:54:48 +02:00
James Cole
178df1ed4a Update qodana.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 06:24:06 +02:00
James Cole
28749e2513 Update qodana.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 06:21:03 +02:00
James Cole
6cbe57ef40 Update qodana.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2023-05-28 06:17:34 +02:00
James Cole
13d3b86309 Fix #7557 2023-05-28 06:07:26 +02:00
James Cole
cf8f43cdf2 Merge tag 'v6.0.11' into develop
v6.0.11
2023-05-27 07:12:28 +02:00
James Cole
cc83268b2c Merge branch 'release/v6.0.11' 2023-05-27 07:12:26 +02:00
James Cole
8f23b47a78 Meta files for new release. 2023-05-27 07:12:04 +02:00
James Cole
529611170c Fix #7541 2023-05-27 06:42:10 +02:00
James Cole
c1114e889e Fix #7546 2023-05-27 06:40:23 +02:00
James Cole
d20e03a7b6 Merge pull request #7556 from firefly-iii/fix-7547
Fix 7547
2023-05-27 06:37:00 +02:00
James Cole
6303233bdf Fix #7547 2023-05-27 06:36:24 +02:00
James Cole
baa8c00144 Merge pull request #7555 from firefly-iii/fix-7549
Fix #7549
2023-05-27 05:56:07 +02:00
James Cole
e6daaa5b6d Fix #7549 2023-05-27 05:55:41 +02:00
James Cole
f711fcfd52 Merge pull request #7535 from ChrisWin22/withdraw-from-piggy-banks
Withdraw from piggy banks
2023-05-24 08:22:41 +02:00
Christian Desktop
74992e95f2 Withdrawal directly from Piggy Bank - Fixes #6631 2023-05-24 00:13:46 -06:00
James Cole
20c8c1043f Update languages and rephrase sentence. 2023-05-24 06:40:31 +02:00
James Cole
f00898afba Merge pull request #7533 from firefly-iii/dependabot/composer/develop/laravel/ui-4.2.2
Bump laravel/ui from 4.2.1 to 4.2.2
2023-05-22 06:25:51 +02:00
dependabot[bot]
95b431535e Bump laravel/ui from 4.2.1 to 4.2.2
Bumps [laravel/ui](https://github.com/laravel/ui) from 4.2.1 to 4.2.2.
- [Release notes](https://github.com/laravel/ui/releases)
- [Changelog](https://github.com/laravel/ui/blob/4.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/ui/compare/v4.2.1...v4.2.2)

---
updated-dependencies:
- dependency-name: laravel/ui
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 04:18:35 +00:00
James Cole
cafd8a9674 Merge pull request #7534 from firefly-iii/dependabot/npm_and_yarn/develop/vue/compiler-sfc-3.3.4
Bump @vue/compiler-sfc from 3.3.2 to 3.3.4
2023-05-22 06:18:14 +02:00
James Cole
e1e7f914f9 Merge pull request #7532 from firefly-iii/dependabot/composer/develop/guzzlehttp/guzzle-7.7.0
Bump guzzlehttp/guzzle from 7.6.0 to 7.7.0
2023-05-22 06:18:02 +02:00
James Cole
19c2f7d2bf Merge pull request #7531 from firefly-iii/dependabot/composer/develop/fakerphp/faker-1.22.0
Bump fakerphp/faker from 1.21.0 to 1.22.0
2023-05-22 06:17:55 +02:00
James Cole
7daacd9b66 Merge pull request #7530 from firefly-iii/dependabot/composer/develop/laravel/framework-10.11.0
Bump laravel/framework from 10.10.1 to 10.11.0
2023-05-22 06:17:47 +02:00
dependabot[bot]
af715de566 Bump @vue/compiler-sfc from 3.3.2 to 3.3.4
Bumps [@vue/compiler-sfc](https://github.com/vuejs/core/tree/HEAD/packages/compiler-sfc) from 3.3.2 to 3.3.4.
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.3.4/packages/compiler-sfc)

---
updated-dependencies:
- dependency-name: "@vue/compiler-sfc"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 03:57:37 +00:00
dependabot[bot]
93e3c89f20 Bump guzzlehttp/guzzle from 7.6.0 to 7.7.0
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.6.0 to 7.7.0.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.7/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.6.0...7.7.0)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 03:56:53 +00:00
dependabot[bot]
b0456c5252 Bump fakerphp/faker from 1.21.0 to 1.22.0
Bumps [fakerphp/faker](https://github.com/FakerPHP/Faker) from 1.21.0 to 1.22.0.
- [Release notes](https://github.com/FakerPHP/Faker/releases)
- [Changelog](https://github.com/FakerPHP/Faker/blob/main/CHANGELOG.md)
- [Commits](https://github.com/FakerPHP/Faker/compare/v1.21.0...v1.22.0)

---
updated-dependencies:
- dependency-name: fakerphp/faker
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 03:56:46 +00:00
dependabot[bot]
f7fa03ddd8 Bump laravel/framework from 10.10.1 to 10.11.0
Bumps [laravel/framework](https://github.com/laravel/framework) from 10.10.1 to 10.11.0.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/10.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v10.10.1...v10.11.0)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-22 03:56:41 +00:00
James Cole
4c78e23a9c Merge pull request #7523 from firefly-iii/fix-7522
Fix 7522
2023-05-19 05:44:33 +02:00
James Cole
79c2065471 fix: Add relevant periods to addPeriod 2023-05-19 05:43:50 +02:00
James Cole
c19b89ac93 Fix: budget amounts 2023-05-19 05:39:21 +02:00
James Cole
62a1837d61 fix: debug would always report midnight. 2023-05-19 05:38:50 +02:00
James Cole
56b34aa624 Merge pull request #7517 from firefly-iii/fix-7516
Fix #7516
2023-05-18 05:38:42 +02:00
James Cole
e8392155f9 Fix #7516 2023-05-18 05:38:17 +02:00
James Cole
6d532470e6 Merge pull request #7515 from firefly-iii/fix-7514
Fix #7514
2023-05-17 15:20:09 +02:00
James Cole
15f683ef7e Fix #7514 2023-05-17 15:19:27 +02:00
James Cole
18ba2e563e Merge pull request #7513 from firefly-iii/fix-7505
Fix #7505
2023-05-17 07:02:39 +02:00
James Cole
63984f1c37 Fix #7505 2023-05-17 07:02:08 +02:00
James Cole
3c082dcf0e Restore cron options. 2023-05-16 21:04:06 +02:00
James Cole
090eb55226 Merge pull request #7502 from firefly-iii/dependabot/composer/develop/guzzlehttp/guzzle-7.6.0
Bump guzzlehttp/guzzle from 7.5.1 to 7.6.0
2023-05-15 06:35:17 +02:00
James Cole
4706cd44de Fix rounding issues. 2023-05-15 06:33:30 +02:00
James Cole
cf7c01e5d0 Merge pull request #7503 from firefly-iii/feat/adjusted-budget
feat: a budget type that will rollover but also incorporate overspend…
2023-05-15 06:18:23 +02:00
James Cole
0b5e0a268a feat: a budget type that will rollover but also incorporate overspending from the previous period (if any) 2023-05-15 06:18:02 +02:00
dependabot[bot]
9eea4497e5 Bump guzzlehttp/guzzle from 7.5.1 to 7.6.0
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.5.1 to 7.6.0.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.6/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.5.1...7.6.0)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-15 03:56:23 +00:00
James Cole
63fdc2487f Merge pull request #7499 from firefly-iii/remove-logging
Remove logging
2023-05-13 06:43:30 +02:00
James Cole
cf59da7e0c Remove logging 2023-05-13 06:43:07 +02:00
James Cole
e0621affb6 Merge tag 'v6.0.10' into develop
v6.0.10
2023-05-13 06:34:38 +02:00
James Cole
6d0906c37b Merge branch 'release/v6.0.10' 2023-05-13 06:34:37 +02:00
James Cole
a3ede0c6f6 Meta files for new release. 2023-05-13 06:34:12 +02:00
James Cole
72eab3c0eb Merge pull request #7498 from firefly-iii/fix-7478
Fix #7478
2023-05-13 06:17:44 +02:00
James Cole
c530961546 Fix #7478 2023-05-13 06:17:22 +02:00
James Cole
dd7aba0b51 Merge pull request #7497 from firefly-iii/fix-7448-2
Fix #7448
2023-05-13 06:09:24 +02:00
James Cole
7c54e17a30 Fix #7448 2023-05-13 06:09:04 +02:00
James Cole
342d72b0a6 Merge pull request #7495 from firefly-iii/expand-fix
Fix decimals command expanded.
2023-05-13 06:07:15 +02:00
James Cole
22ee504e52 Fix decimals command expanded. 2023-05-13 05:56:49 +02:00
James Cole
4880ee850e Merge pull request #7494 from firefly-iii/fix-7444
Fix 7444
2023-05-13 05:32:05 +02:00
James Cole
b45ce27817 Fix #7444 2023-05-13 05:31:41 +02:00
James Cole
dfad93d9ec Merge pull request #7473 from firefly-iii/dependabot/npm_and_yarn/develop/uiv-1.4.3
Bump uiv from 1.4.2 to 1.4.3
2023-05-08 06:16:02 +02:00
James Cole
52712c8cb2 Merge pull request #7472 from firefly-iii/dependabot/composer/develop/ergebnis/phpstan-rules-2.0.0
Bump ergebnis/phpstan-rules from 1.0.0 to 2.0.0
2023-05-08 06:15:52 +02:00
James Cole
740874e654 Merge pull request #7471 from firefly-iii/dependabot/composer/develop/spatie/laravel-ignition-2.1.1
Bump spatie/laravel-ignition from 2.1.0 to 2.1.1
2023-05-08 06:15:44 +02:00
James Cole
0f1f37a5df Merge pull request #7470 from firefly-iii/dependabot/composer/develop/laravel/sanctum-3.2.5
Bump laravel/sanctum from 3.2.4 to 3.2.5
2023-05-08 06:07:43 +02:00
dependabot[bot]
d609cbfb16 Bump uiv from 1.4.2 to 1.4.3
Bumps [uiv](https://github.com/uiv-lib/uiv) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/uiv-lib/uiv/releases)
- [Commits](https://github.com/uiv-lib/uiv/compare/v1.4.2...v1.4.3)

---
updated-dependencies:
- dependency-name: uiv
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 03:56:47 +00:00
dependabot[bot]
2375857c92 Bump ergebnis/phpstan-rules from 1.0.0 to 2.0.0
Bumps [ergebnis/phpstan-rules](https://github.com/ergebnis/phpstan-rules) from 1.0.0 to 2.0.0.
- [Release notes](https://github.com/ergebnis/phpstan-rules/releases)
- [Changelog](https://github.com/ergebnis/phpstan-rules/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/phpstan-rules/compare/1.0.0...2.0.0)

---
updated-dependencies:
- dependency-name: ergebnis/phpstan-rules
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 03:56:37 +00:00
dependabot[bot]
10275eb832 Bump spatie/laravel-ignition from 2.1.0 to 2.1.1
Bumps [spatie/laravel-ignition](https://github.com/spatie/laravel-ignition) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/spatie/laravel-ignition/releases)
- [Changelog](https://github.com/spatie/laravel-ignition/blob/main/CHANGELOG.md)
- [Commits](https://github.com/spatie/laravel-ignition/compare/2.1.0...2.1.1)

---
updated-dependencies:
- dependency-name: spatie/laravel-ignition
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 03:56:33 +00:00
dependabot[bot]
108867b2ef Bump laravel/sanctum from 3.2.4 to 3.2.5
Bumps [laravel/sanctum](https://github.com/laravel/sanctum) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/laravel/sanctum/releases)
- [Changelog](https://github.com/laravel/sanctum/blob/3.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/sanctum/compare/v3.2.4...v3.2.5)

---
updated-dependencies:
- dependency-name: laravel/sanctum
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 03:56:26 +00:00
James Cole
e5a77a86f9 Fix a few commands. 2023-05-07 20:17:29 +02:00
James Cole
309d3e8e95 Fix missing account validation step. 2023-05-06 15:59:31 +02:00
James Cole
1ef9b83180 Merge pull request #7466 from firefly-iii/fix-7456
Fix #7456
2023-05-06 15:29:56 +02:00
James Cole
85757e1a20 Fix #7456 2023-05-06 15:29:29 +02:00
James Cole
e2a18e0e7c Merge pull request #7461 from eandersons/Focus-on-MFA-input-field
Focus on MFA input field on page load
2023-05-04 21:05:53 +02:00
Edgars
056af8fd8a Focus on MFA input field on page load 2023-05-04 15:13:47 +03:00
James Cole
c72a63f218 Merge pull request #7458 from firefly-iii/fix-7457
Fix #7457
2023-05-03 05:59:30 +02:00
James Cole
fb823ed422 Fix #7457 2023-05-03 05:59:10 +02:00
James Cole
3fae6c0cac Merge pull request #7451 from firefly-iii/dependabot/composer/develop/laravel/passport-11.8.7
Bump laravel/passport from 11.8.6 to 11.8.7
2023-05-02 08:21:36 +02:00
James Cole
55b1e22d37 Merge pull request #7452 from firefly-iii/dependabot/npm_and_yarn/develop/date-fns-2.30.0
Bump date-fns from 2.29.3 to 2.30.0
2023-05-02 08:21:27 +02:00
James Cole
e6b95c7894 Merge pull request #7450 from firefly-iii/dependabot/composer/develop/symfony/mailgun-mailer-6.2.10
Bump symfony/mailgun-mailer from 6.2.7 to 6.2.10
2023-05-01 10:42:30 +02:00
dependabot[bot]
ea2f9e4919 Bump symfony/mailgun-mailer from 6.2.7 to 6.2.10
Bumps [symfony/mailgun-mailer](https://github.com/symfony/mailgun-mailer) from 6.2.7 to 6.2.10.
- [Release notes](https://github.com/symfony/mailgun-mailer/releases)
- [Changelog](https://github.com/symfony/mailgun-mailer/blob/6.2/CHANGELOG.md)
- [Commits](https://github.com/symfony/mailgun-mailer/compare/v6.2.7...v6.2.10)

---
updated-dependencies:
- dependency-name: symfony/mailgun-mailer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 07:46:51 +00:00
James Cole
08bd405e29 Merge pull request #7449 from firefly-iii/dependabot/composer/develop/symfony/http-client-6.2.10 2023-05-01 09:45:59 +02:00
dependabot[bot]
8294b2d526 Bump date-fns from 2.29.3 to 2.30.0
Bumps [date-fns](https://github.com/date-fns/date-fns) from 2.29.3 to 2.30.0.
- [Release notes](https://github.com/date-fns/date-fns/releases)
- [Changelog](https://github.com/date-fns/date-fns/blob/v2.30.0/CHANGELOG.md)
- [Commits](https://github.com/date-fns/date-fns/compare/v2.29.3...v2.30.0)

---
updated-dependencies:
- dependency-name: date-fns
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:57:00 +00:00
dependabot[bot]
b521fb8fae Bump laravel/passport from 11.8.6 to 11.8.7
Bumps [laravel/passport](https://github.com/laravel/passport) from 11.8.6 to 11.8.7.
- [Release notes](https://github.com/laravel/passport/releases)
- [Changelog](https://github.com/laravel/passport/blob/11.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/passport/compare/v11.8.6...v11.8.7)

---
updated-dependencies:
- dependency-name: laravel/passport
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:56:45 +00:00
dependabot[bot]
3e9789d5e6 Bump symfony/http-client from 6.2.9 to 6.2.10
Bumps [symfony/http-client](https://github.com/symfony/http-client) from 6.2.9 to 6.2.10.
- [Release notes](https://github.com/symfony/http-client/releases)
- [Changelog](https://github.com/symfony/http-client/blob/6.2/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-client/compare/v6.2.9...v6.2.10)

---
updated-dependencies:
- dependency-name: symfony/http-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 03:56:27 +00:00
James Cole
13b029d7f0 Merge pull request #7447 from firefly-iii/fix-7446
Fix #7446
2023-04-30 19:13:34 +02:00
James Cole
59427ba5c2 Fix #7446 2023-04-30 19:12:49 +02:00
James Cole
46bba9d799 Various optimizations in budget limit handling. 2023-04-30 06:45:25 +02:00
James Cole
0ef1d1834f Fix template 2023-04-29 19:19:53 +02:00
James Cole
e39b2f5355 Fix template 2023-04-29 17:39:01 +02:00
James Cole
03dae53714 Fix template 2023-04-29 14:40:12 +02:00
James Cole
6be6187532 Add base build info. 2023-04-29 11:15:30 +02:00
James Cole
4c26f613ee Merge pull request #7443 from firefly-iii/expand-health-check
Change health endpoint to include a DB check.
2023-04-29 07:44:56 +02:00
James Cole
765de2eeba Change health endpoint to include a DB check. 2023-04-29 07:44:37 +02:00
James Cole
49b1fef7ff Merge pull request #7442 from firefly-iii/fix-iban-check
Don't trigger on empty ibans.
2023-04-29 07:09:05 +02:00
James Cole
36157afc6a Don't trigger on empty ibans. 2023-04-29 07:08:11 +02:00
James Cole
c5c3638dbc Merge tag '6.0.9' into develop
v6.0.9
2023-04-28 09:27:43 +02:00
695 changed files with 27452 additions and 26248 deletions

View File

@@ -379,16 +379,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.16.0",
"version": "v3.17.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "d40f9436e1c448d309fa995ab9c14c5c7a96f2dc"
"reference": "3f0ed862f22386c55a767461ef5083bddceeed79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d40f9436e1c448d309fa995ab9c14c5c7a96f2dc",
"reference": "d40f9436e1c448d309fa995ab9c14c5c7a96f2dc",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/3f0ed862f22386c55a767461ef5083bddceeed79",
"reference": "3f0ed862f22386c55a767461ef5083bddceeed79",
"shasum": ""
},
"require": {
@@ -463,7 +463,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.16.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.17.0"
},
"funding": [
{
@@ -471,7 +471,7 @@
"type": "github"
}
],
"time": "2023-04-02T19:30:06+00:00"
"time": "2023-05-22T19:59:32+00:00"
},
{
"name": "psr/cache",
@@ -677,16 +677,16 @@
},
{
"name": "sebastian/diff",
"version": "5.0.1",
"version": "5.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "aae9a0a43bff37bd5d8d0311426c87bf36153f02"
"reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/aae9a0a43bff37bd5d8d0311426c87bf36153f02",
"reference": "aae9a0a43bff37bd5d8d0311426c87bf36153f02",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b",
"reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b",
"shasum": ""
},
"require": {
@@ -732,7 +732,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy",
"source": "https://github.com/sebastianbergmann/diff/tree/5.0.1"
"source": "https://github.com/sebastianbergmann/diff/tree/5.0.3"
},
"funding": [
{
@@ -740,27 +740,27 @@
"type": "github"
}
],
"time": "2023-03-23T05:12:41+00:00"
"time": "2023-05-01T07:48:21+00:00"
},
{
"name": "symfony/console",
"version": "v6.2.8",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "3582d68a64a86ec25240aaa521ec8bc2342b369b"
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/3582d68a64a86ec25240aaa521ec8bc2342b369b",
"reference": "3582d68a64a86ec25240aaa521ec8bc2342b369b",
"url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0"
},
"conflict": {
@@ -782,12 +782,6 @@
"symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"autoload": {
"psr-4": {
@@ -820,7 +814,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.2.8"
"source": "https://github.com/symfony/console/tree/v6.3.0"
},
"funding": [
{
@@ -836,20 +830,20 @@
"type": "tidelift"
}
],
"time": "2023-03-29T21:42:15+00:00"
"time": "2023-05-29T12:49:39+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.2.1",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e"
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
"reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"shasum": ""
},
"require": {
@@ -858,7 +852,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.3-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -887,7 +881,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
},
"funding": [
{
@@ -903,28 +897,29 @@
"type": "tidelift"
}
],
"time": "2023-03-01T10:25:55+00:00"
"time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v6.2.8",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "04046f35fd7d72f9646e721fc2ecb8f9c67d3339"
"reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/04046f35fd7d72f9646e721fc2ecb8f9c67d3339",
"reference": "04046f35fd7d72f9646e721fc2ecb8f9c67d3339",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa",
"reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/event-dispatcher-contracts": "^2|^3"
"symfony/event-dispatcher-contracts": "^2.5|^3"
},
"conflict": {
"symfony/dependency-injection": "<5.4"
"symfony/dependency-injection": "<5.4",
"symfony/service-contracts": "<2.5"
},
"provide": {
"psr/event-dispatcher-implementation": "1.0",
@@ -937,13 +932,9 @@
"symfony/error-handler": "^5.4|^6.0",
"symfony/expression-language": "^5.4|^6.0",
"symfony/http-foundation": "^5.4|^6.0",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/service-contracts": "^2.5|^3",
"symfony/stopwatch": "^5.4|^6.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"autoload": {
"psr-4": {
@@ -970,7 +961,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v6.2.8"
"source": "https://github.com/symfony/event-dispatcher/tree/v6.3.0"
},
"funding": [
{
@@ -986,33 +977,30 @@
"type": "tidelift"
}
],
"time": "2023-03-20T16:06:02+00:00"
"time": "2023-04-21T14:41:17+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v3.2.1",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd"
"reference": "a76aed96a42d2b521153fb382d418e30d18b59df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ad3b6f1e4e2da5690fefe075cd53a238646d8dd",
"reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df",
"reference": "a76aed96a42d2b521153fb382d418e30d18b59df",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/event-dispatcher": "^1"
},
"suggest": {
"symfony/event-dispatcher-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.3-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -1049,7 +1037,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.2.1"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0"
},
"funding": [
{
@@ -1065,20 +1053,20 @@
"type": "tidelift"
}
],
"time": "2023-03-01T10:32:47+00:00"
"time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/filesystem",
"version": "v6.2.7",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "82b6c62b959f642d000456f08c6d219d749215b3"
"reference": "97b698e1d77d356304def77a8d0cd73090b359ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/82b6c62b959f642d000456f08c6d219d749215b3",
"reference": "82b6c62b959f642d000456f08c6d219d749215b3",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/97b698e1d77d356304def77a8d0cd73090b359ea",
"reference": "97b698e1d77d356304def77a8d0cd73090b359ea",
"shasum": ""
},
"require": {
@@ -1112,7 +1100,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v6.2.7"
"source": "https://github.com/symfony/filesystem/tree/v6.3.0"
},
"funding": [
{
@@ -1128,20 +1116,20 @@
"type": "tidelift"
}
],
"time": "2023-02-14T08:44:56+00:00"
"time": "2023-05-30T17:12:32+00:00"
},
{
"name": "symfony/finder",
"version": "v6.2.7",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "20808dc6631aecafbe67c186af5dcb370be3a0eb"
"reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/20808dc6631aecafbe67c186af5dcb370be3a0eb",
"reference": "20808dc6631aecafbe67c186af5dcb370be3a0eb",
"url": "https://api.github.com/repos/symfony/finder/zipball/d9b01ba073c44cef617c7907ce2419f8d00d75e2",
"reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2",
"shasum": ""
},
"require": {
@@ -1176,7 +1164,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v6.2.7"
"source": "https://github.com/symfony/finder/tree/v6.3.0"
},
"funding": [
{
@@ -1192,25 +1180,25 @@
"type": "tidelift"
}
],
"time": "2023-02-16T09:57:23+00:00"
"time": "2023-04-02T01:25:41+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v6.2.7",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "aa0e85b53bbb2b4951960efd61d295907eacd629"
"reference": "a10f19f5198d589d5c33333cffe98dc9820332dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/aa0e85b53bbb2b4951960efd61d295907eacd629",
"reference": "aa0e85b53bbb2b4951960efd61d295907eacd629",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd",
"reference": "a10f19f5198d589d5c33333cffe98dc9820332dd",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.1|^3"
"symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
"autoload": {
@@ -1243,7 +1231,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v6.2.7"
"source": "https://github.com/symfony/options-resolver/tree/v6.3.0"
},
"funding": [
{
@@ -1259,7 +1247,7 @@
"type": "tidelift"
}
],
"time": "2023-02-14T08:44:56+00:00"
"time": "2023-05-12T14:21:09+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -1755,16 +1743,16 @@
},
{
"name": "symfony/process",
"version": "v6.2.8",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "75ed64103df4f6615e15a7fe38b8111099f47416"
"reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/75ed64103df4f6615e15a7fe38b8111099f47416",
"reference": "75ed64103df4f6615e15a7fe38b8111099f47416",
"url": "https://api.github.com/repos/symfony/process/zipball/8741e3ed7fe2e91ec099e02446fb86667a0f1628",
"reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628",
"shasum": ""
},
"require": {
@@ -1796,7 +1784,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v6.2.8"
"source": "https://github.com/symfony/process/tree/v6.3.0"
},
"funding": [
{
@@ -1812,20 +1800,20 @@
"type": "tidelift"
}
],
"time": "2023-03-09T16:20:02+00:00"
"time": "2023-05-19T08:06:44+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.2.1",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "a8c9cedf55f314f3a186041d19537303766df09a"
"reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a",
"reference": "a8c9cedf55f314f3a186041d19537303766df09a",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4",
"reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4",
"shasum": ""
},
"require": {
@@ -1835,13 +1823,10 @@
"conflict": {
"ext-psr": "<1.1|>=2"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.3-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -1881,7 +1866,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.2.1"
"source": "https://github.com/symfony/service-contracts/tree/v3.3.0"
},
"funding": [
{
@@ -1897,25 +1882,25 @@
"type": "tidelift"
}
],
"time": "2023-03-01T10:32:47+00:00"
"time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/stopwatch",
"version": "v6.2.7",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
"reference": "f3adc98c1061875dd2edcd45e5b04e63d0e29f8f"
"reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/f3adc98c1061875dd2edcd45e5b04e63d0e29f8f",
"reference": "f3adc98c1061875dd2edcd45e5b04e63d0e29f8f",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2",
"reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/service-contracts": "^1|^2|^3"
"symfony/service-contracts": "^2.5|^3"
},
"type": "library",
"autoload": {
@@ -1943,7 +1928,7 @@
"description": "Provides a way to profile code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/stopwatch/tree/v6.2.7"
"source": "https://github.com/symfony/stopwatch/tree/v6.3.0"
},
"funding": [
{
@@ -1959,20 +1944,20 @@
"type": "tidelift"
}
],
"time": "2023-02-14T08:44:56+00:00"
"time": "2023-02-16T10:14:28+00:00"
},
{
"name": "symfony/string",
"version": "v6.2.8",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef"
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef",
"reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef",
"url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"shasum": ""
},
"require": {
@@ -1983,13 +1968,13 @@
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/translation-contracts": "<2.0"
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
"symfony/error-handler": "^5.4|^6.0",
"symfony/http-client": "^5.4|^6.0",
"symfony/intl": "^6.2",
"symfony/translation-contracts": "^2.0|^3.0",
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^5.4|^6.0"
},
"type": "library",
@@ -2029,7 +2014,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.2.8"
"source": "https://github.com/symfony/string/tree/v6.3.0"
},
"funding": [
{
@@ -2045,7 +2030,7 @@
"type": "tidelift"
}
],
"time": "2023-03-20T16:06:02+00:00"
"time": "2023-03-21T21:06:29+00:00"
}
],
"packages-dev": [],

View File

@@ -32,7 +32,10 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd $SCRIPT_DIR/php-cs-fixer
composer update
rm -f .php-cs-fixer.cache
echo 'Removed cache...'
echo 'Running...'
PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php --allow-risky=yes
echo 'Done!'
cd $SCRIPT_DIR/..
exit 0

View File

@@ -13,6 +13,7 @@ hu_HU
id_ID
it_IT
ja_JP
ko_KR
nb_NO
nl_NL
pl_PL

View File

@@ -62,7 +62,7 @@ APP_LOG_LEVEL=notice
AUDIT_LOG_LEVEL=info
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: https://docs.firefly-iii.org/support/faq
# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
# Use "pgsql" for PostgreSQL
# Use "mysql" for MySQL and MariaDB.
@@ -134,7 +134,7 @@ COOKIE_SECURE=false
COOKIE_SAMESITE=lax
# If you want Firefly III to email you, update these settings
# For instructions, see: https://docs.firefly-iii.org/advanced-installation/email
# For instructions, see: https://docs.firefly-iii.org/firefly-iii/advanced-installation/email/#email
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
MAIL_MAILER=log
MAIL_HOST=null
@@ -163,9 +163,8 @@ SEND_ERROR_MESSAGE=true
# These messages contain (sensitive) transaction information:
SEND_REPORT_JOURNALS=true
# Set this value to true if you want to set the location
# of certain things, like transactions. Since this involves an external service, it's optional
# and disabled by default.
# Set this value to true if you want to set the location of certain things, like transactions.
# Since this involves an external service, it's optional and disabled by default.
ENABLE_EXTERNAL_MAP=false
# Set this value to true if you want Firefly III to download currency exchange rates
@@ -188,7 +187,7 @@ MAP_DEFAULT_ZOOM=6
# - 'web' (default, uses built in DB)
# - 'remote_user_guard' for Authelia etc
# Read more about these settings in the documentation.
# https://docs.firefly-iii.org/advanced-installation/authentication
# https://docs.firefly-iii.org/firefly-iii/advanced-installation/authentication
#
# LDAP is no longer supported :(
#

View File

@@ -1,3 +1,3 @@
# [Contributing guidelines](https://docs.firefly-iii.org/other-pages/contributing)
# [Contributing guidelines](https://docs.firefly-iii.org/firefly-iii/support/#contributing-code)
[Contributing guidelines](https://docs.firefly-iii.org/other-pages/contributing)
[Contributing guidelines](https://docs.firefly-iii.org/firefly-iii/support/#contributing-code)

View File

@@ -56,9 +56,12 @@ jobs:
const workflows = [
'cleanup.yml',
'closed-issues.yml',
'depsreview.yaml',
'laravel.yml',
'lock.yml',
'qodana.yml',
'sonarcloud.yml',
'stale.yml'
]

View File

@@ -13,10 +13,11 @@ jobs:
message: |
Hi there! This is an automatic reply. `Share and enjoy`
This issue is now closed. Please be aware that closed issues are not actively monitored. If you reply, you may get no response.
This issue is now 🔒 closed. Please be aware that closed issues are **not** watched.
- If the original bug is not actually fixed, please feel free to open a new issue. Please refer to this issue for clarity.
- Follow-up questions can also be posted in a new [discussion](https://github.com/firefly-iii/firefly-iii/discussions/)
- If the original bug is not actually fixed, please feel free to open [a new issue](https://github.com/firefly-iii/firefly-iii/issues/new/choose). Please refer to this issue for clarity.
- Follow-up questions must be posted in a new [discussion](https://github.com/firefly-iii/firefly-iii/discussions/)
- Further replies to this issue will get **no response**.
Thank you for your consideration.
Thank you for your contributions.
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -5,8 +5,6 @@ on:
branches:
- main
- develop
pull_request:
types: [ opened, synchronize, reopened ]
jobs:
qodana:
runs-on: ubuntu-latest

19
.github/workflows/sonarcloud.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Sonarcloud
on:
push:
branches:
- main
- develop
jobs:
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GH_ACTIONS_PERSONAL_ACCESS_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@@ -81,8 +81,9 @@ class AccountController extends Controller
$query = $data['query'];
$date = $data['date'] ?? today(config('app.timezone'));
$return = [];
$result = $this->repository->searchAccount((string)$query, $types, $data['limit']);
$return = [];
$result = $this->repository->searchAccount((string)$query, $types, $data['limit']);
// TODO this code is duplicated in the V2 Autocomplete controller, which means this code is due to be deprecated.
$defaultCurrency = app('amount')->getDefaultCurrency();
/** @var Account $account */
@@ -92,7 +93,11 @@ class AccountController extends Controller
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = app('steam')->balance($account, $date);
$nameWithBalance = sprintf('%s (%s)', $account->name, app('amount')->formatAnything($currency, $balance, false));
$nameWithBalance = sprintf(
'%s (%s)',
$account->name,
app('amount')->formatAnything($currency, $balance, false)
);
}
$return[] = [
@@ -109,14 +114,14 @@ class AccountController extends Controller
}
// custom order.
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
usort(
$return,
function ($a, $b) use ($order) {
$pos_a = array_search($a['type'], $order, true);
$pos_b = array_search($b['type'], $order, true);
function ($a, $b) {
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
$posA = array_search($a['type'], $order, true);
$posB = array_search($b['type'], $order, true);
return $pos_a - $pos_b;
return $posA - $posB;
}
);

View File

@@ -113,7 +113,7 @@ class AccountController extends Controller
if (null === $currency) {
$currency = $default;
}
$currentSet = [
$currentSet = [
'label' => $account->name,
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
@@ -125,6 +125,7 @@ class AccountController extends Controller
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
];
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
$currentStart = clone $start;
$range = app('steam')->balanceInRange($account, $start, clone $end);
// 2022-10-11 this method no longer converts to float.

View File

@@ -74,6 +74,42 @@ abstract class Controller extends BaseController
);
}
/**
* Method to help build URL's.
*
* @return string
*/
final protected function buildParams(): string
{
$return = '?';
$params = [];
foreach ($this->parameters as $key => $value) {
if ('page' === $key) {
continue;
}
if ($value instanceof Carbon) {
$params[$key] = $value->format('Y-m-d');
continue;
}
$params[$key] = $value;
}
return $return.http_build_query($params);
}
/**
* @return Manager
*/
final protected function getManager(): Manager
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
return $manager;
}
/**
* Method to grab all parameters from the URL.
*
@@ -110,7 +146,13 @@ abstract class Controller extends BaseController
$obj = Carbon::parse($date);
} catch (InvalidDateException|InvalidFormatException $e) {
// don't care
app('log')->warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', substr($date, 0, 20), $e->getMessage()));
app('log')->warning(
sprintf(
'Ignored invalid date "%s" in API controller parameter check: %s',
substr($date, 0, 20),
$e->getMessage()
)
);
}
}
$bag->set($field, $obj);
@@ -169,41 +211,4 @@ abstract class Controller extends BaseController
return $bag;
}
/**
* Method to help build URL's.
*
* @return string
*/
final protected function buildParams(): string
{
$return = '?';
$params = [];
foreach ($this->parameters as $key => $value) {
if ('page' === $key) {
continue;
}
if ($value instanceof Carbon) {
$params[$key] = $value->format('Y-m-d');
continue;
}
$params[$key] = $value;
}
return $return.http_build_query($params);
}
/**
* @return Manager
*/
final protected function getManager(): Manager
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
return $manager;
}
}

View File

@@ -201,91 +201,6 @@ class DestroyController extends Controller
return response()->json([], 204);
}
/**
*
*/
private function destroyBudgets(): void
{
/** @var AvailableBudgetRepositoryInterface $abRepository */
$abRepository = app(AvailableBudgetRepositoryInterface::class);
$abRepository->destroyAll();
/** @var BudgetLimitRepositoryInterface $blRepository */
$blRepository = app(BudgetLimitRepositoryInterface::class);
$blRepository->destroyAll();
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgetRepository->destroyAll();
}
/**
*
*/
private function destroyBills(): void
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyPiggyBanks(): void
{
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRules(): void
{
/** @var RuleGroupRepositoryInterface $repository */
$repository = app(RuleGroupRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRecurringTransactions(): void
{
/** @var RecurringRepositoryInterface $repository */
$repository = app(RecurringRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyCategories(): void
{
/** @var CategoryRepositoryInterface $categoryRepos */
$categoryRepos = app(CategoryRepositoryInterface::class);
$categoryRepos->destroyAll();
}
/**
*
*/
private function destroyTags(): void
{
/** @var TagRepositoryInterface $tagRepository */
$tagRepository = app(TagRepositoryInterface::class);
$tagRepository->destroyAll();
}
private function destroyObjectGroups(): void
{
/** @var ObjectGroupRepositoryInterface $repository */
$repository = app(ObjectGroupRepositoryInterface::class);
$repository->deleteAll();
}
/**
* @param array $types
*/
@@ -311,6 +226,91 @@ class DestroyController extends Controller
}
}
/**
*
*/
private function destroyBills(): void
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyBudgets(): void
{
/** @var AvailableBudgetRepositoryInterface $abRepository */
$abRepository = app(AvailableBudgetRepositoryInterface::class);
$abRepository->destroyAll();
/** @var BudgetLimitRepositoryInterface $blRepository */
$blRepository = app(BudgetLimitRepositoryInterface::class);
$blRepository->destroyAll();
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgetRepository->destroyAll();
}
/**
*
*/
private function destroyCategories(): void
{
/** @var CategoryRepositoryInterface $categoryRepos */
$categoryRepos = app(CategoryRepositoryInterface::class);
$categoryRepos->destroyAll();
}
private function destroyObjectGroups(): void
{
/** @var ObjectGroupRepositoryInterface $repository */
$repository = app(ObjectGroupRepositoryInterface::class);
$repository->deleteAll();
}
/**
*
*/
private function destroyPiggyBanks(): void
{
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRecurringTransactions(): void
{
/** @var RecurringRepositoryInterface $repository */
$repository = app(RecurringRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRules(): void
{
/** @var RuleGroupRepositoryInterface $repository */
$repository = app(RuleGroupRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyTags(): void
{
/** @var TagRepositoryInterface $tagRepository */
$tagRepository = app(TagRepositoryInterface::class);
$tagRepository->destroyAll();
}
/**
* @param array $types
*/

View File

@@ -69,34 +69,6 @@ class ExportController extends Controller
return $this->returnExport('accounts');
}
/**
* @param string $key
*
* @return LaravelResponse
* @throws FireflyException
*/
private function returnExport(string $key): LaravelResponse
{
$date = date('Y-m-d-H-i-s');
$fileName = sprintf('%s-export-%s.csv', $date, $key);
$data = $this->exporter->export();
/** @var LaravelResponse $response */
$response = response($data[$key]);
$response
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename='.$fileName)
->header('Content-Transfer-Encoding', 'binary')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', (string)strlen($data[$key]));
return $response;
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportBills
@@ -228,4 +200,32 @@ class ExportController extends Controller
return $this->returnExport('transactions');
}
/**
* @param string $key
*
* @return LaravelResponse
* @throws FireflyException
*/
private function returnExport(string $key): LaravelResponse
{
$date = date('Y-m-d-H-i-s');
$fileName = sprintf('%s-export-%s.csv', $date, $key);
$data = $this->exporter->export();
/** @var LaravelResponse $response */
$response = response($data[$key]);
$response
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename='.$fileName)
->header('Content-Transfer-Encoding', 'binary')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', (string)strlen($data[$key]));
return $response;
}
}

View File

@@ -43,6 +43,7 @@ class PurgeController extends Controller
* TODO cleanup and use repositories.
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/purgeData
*
* @return JsonResponse
*/
public function purge(): JsonResponse

View File

@@ -29,8 +29,8 @@ use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
use Preferences;
/**

View File

@@ -34,8 +34,8 @@ use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
/**
* Class StoreController

View File

@@ -97,21 +97,6 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransactionByJournal
*
* Show a single transaction, by transaction journal.
*
* @param TransactionJournal $transactionJournal
*
* @return JsonResponse
*/
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
{
return $this->show($transactionJournal->transactionGroup);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransaction
@@ -148,4 +133,19 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransactionByJournal
*
* Show a single transaction, by transaction journal.
*
* @param TransactionJournal $transactionJournal
*
* @return JsonResponse
*/
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
{
return $this->show($transactionJournal->transactionGroup);
}
}

View File

@@ -35,9 +35,9 @@ use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use Validator;
/**

View File

@@ -32,8 +32,8 @@ use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**

View File

@@ -97,6 +97,35 @@ class UpdateController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/enableCurrency
*
* Enable a currency.
*
* @param TransactionCurrency $currency
*
* @return JsonResponse
* @throws FireflyException
* @throws JsonException
*/
public function enable(TransactionCurrency $currency): JsonResponse
{
$this->repository->enable($currency);
$manager = $this->getManager();
$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', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/defaultCurrency
@@ -128,35 +157,6 @@ class UpdateController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/enableCurrency
*
* Enable a currency.
*
* @param TransactionCurrency $currency
*
* @return JsonResponse
* @throws FireflyException
* @throws JsonException
*/
public function enable(TransactionCurrency $currency): JsonResponse
{
$this->repository->enable($currency);
$manager = $this->getManager();
$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', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/updateCurrency

View File

@@ -32,10 +32,10 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use JsonException;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use Illuminate\Support\Facades\Log;
/**
* Class AccountController
@@ -61,12 +61,12 @@ class AccountController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/search/searchAccounts
*
* @param Request $request
*
* @return JsonResponse|Response
* @throws JsonException
*/
public function search(Request $request)
public function search(Request $request): JsonResponse|Response
{
Log::debug('Now in account search()');
$manager = $this->getManager();

View File

@@ -71,6 +71,8 @@ class TransactionController extends Controller
$resource = new Collection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($groups));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
$array = $manager->createData($resource)->toArray();
return response()->json($array)->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -121,6 +121,30 @@ class BasicController extends Controller
return response()->json($return);
}
/**
* Check if date is outside session range.
*
* @param Carbon $date
*
* @param Carbon $start
* @param Carbon $end
*
* @return bool
*/
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;
}
/**
* @param Carbon $start
* @param Carbon $end
@@ -240,44 +264,43 @@ class BasicController extends Controller
* 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->find((int)$currencyId);
if (null === $currency) {
continue;
}
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
$return = [];
/**
* @var array $info
*/
foreach ($paidAmount as $info) {
$amount = bcmul($info['sum'], '-1');
$return[] = [
'key' => sprintf('bills-paid-in-%s', $currency->code),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $currency->symbol]),
'key' => sprintf('bills-paid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['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, $amount, false),
'currency_id' => $info['id'],
'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'],
'value_parsed' => app('amount')->formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
'local_icon' => 'check',
'sub_title' => '',
];
}
foreach ($unpaidAmount as $currencyId => $amount) {
$amount = bcmul($amount, '-1');
$currency = $this->currencyRepos->find((int)$currencyId);
if (null === $currency) {
continue;
}
/**
* @var array $info
*/
foreach ($unpaidAmount as $info) {
$amount = bcmul($info['sum'], '-1');
$return[] = [
'key' => sprintf('bills-unpaid-in-%s', $currency->code),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $currency->symbol]),
'key' => sprintf('bills-unpaid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['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, $amount, false),
'currency_id' => $info['id'],
'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'],
'value_parsed' => app('amount')->formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
'local_icon' => 'calendar-o',
'sub_title' => '',
];
@@ -399,28 +422,4 @@ class BasicController extends Controller
return $return;
}
/**
* Check if date is outside session range.
*
* @param Carbon $date
*
* @param Carbon $start
* @param Carbon $end
*
* @return bool
*/
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;
}
}

View File

@@ -94,42 +94,6 @@ class ConfigurationController extends Controller
return response()->json($return);
}
/**
* Get all config values.
*
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
return [
'is_demo_site' => $isDemoSite?->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => $singleUser?->data,
];
}
/**
* @return array
*/
private function getStaticConfiguration(): array
{
$list = EitherConfigKey::$static;
$return = [];
foreach ($list as $key) {
$return[$key] = config($key);
}
return $return;
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/configuration/getSingleConfiguration
@@ -200,4 +164,40 @@ class ConfigurationController extends Controller
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
}
/**
* Get all config values.
*
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
return [
'is_demo_site' => $isDemoSite?->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => $singleUser?->data,
];
}
/**
* @return array
*/
private function getStaticConfiguration(): array
{
$list = EitherConfigKey::$static;
$return = [];
foreach ($list as $key) {
$return[$key] = config($key);
}
return $return;
}
}

View File

@@ -54,6 +54,10 @@ class CronController extends Controller
$return = [];
$return['recurring_transactions'] = $this->runRecurring($config['force'], $config['date']);
$return['auto_budgets'] = $this->runAutoBudget($config['force'], $config['date']);
if (true === config('cer.enabled')) {
$return['exchange_rates'] = $this->exchangeRatesCronJob($config['force'], $config['date']);
}
$return['bill_warnings'] = $this->billWarningCronJob($config['force'], $config['date']);
return response()->json($return);
}

View File

@@ -122,6 +122,7 @@ class ShowController extends Controller
*
* @param Webhook $webhook
* @param TransactionGroup $group
*
* @return JsonResponse
*/
public function triggerTransaction(Webhook $webhook, TransactionGroup $group): JsonResponse
@@ -141,6 +142,7 @@ class ShowController extends Controller
// trigger event to send them:
event(new RequestedSendWebhookMessages());
return response()->json([], 204);
}
}

View File

@@ -83,6 +83,7 @@ class MoveTransactionsRequest extends FormRequest
/**
* @param Validator $validator
*
* @return void
*/
private function validateMove(Validator $validator): void

View File

@@ -30,9 +30,9 @@ use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\Validation\Api\Data\Bulk\ValidatesBulkTransactionQuery;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
use JsonException;
use Illuminate\Support\Facades\Log;
/**
* Class TransactionRequest

View File

@@ -82,28 +82,6 @@ class GenericRequest extends FormRequest
return $return;
}
/**
*
*/
private function parseAccounts(): void
{
if (0 !== $this->accounts->count()) {
return;
}
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('accounts');
if (is_array($array)) {
foreach ($array as $accountId) {
$accountId = (int)$accountId;
$account = $repository->find($accountId);
if (null !== $account) {
$this->accounts->push($account);
}
}
}
}
/**
* @return Collection
*/
@@ -114,28 +92,6 @@ class GenericRequest extends FormRequest
return $this->bills;
}
/**
*
*/
private function parseBills(): void
{
if (0 !== $this->bills->count()) {
return;
}
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('bills');
if (is_array($array)) {
foreach ($array as $billId) {
$billId = (int)$billId;
$bill = $repository->find($billId);
if (null !== $bill) {
$this->bills->push($bill);
}
}
}
}
/**
* @return Collection
*/
@@ -146,28 +102,6 @@ class GenericRequest extends FormRequest
return $this->budgets;
}
/**
*
*/
private function parseBudgets(): void
{
if (0 !== $this->budgets->count()) {
return;
}
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('budgets');
if (is_array($array)) {
foreach ($array as $budgetId) {
$budgetId = (int)$budgetId;
$budget = $repository->find($budgetId);
if (null !== $budget) {
$this->budgets->push($budget);
}
}
}
}
/**
* @return Collection
*/
@@ -178,28 +112,6 @@ class GenericRequest extends FormRequest
return $this->categories;
}
/**
*
*/
private function parseCategories(): void
{
if (0 !== $this->categories->count()) {
return;
}
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('categories');
if (is_array($array)) {
foreach ($array as $categoryId) {
$categoryId = (int)$categoryId;
$category = $repository->find($categoryId);
if (null !== $category) {
$this->categories->push($category);
}
}
}
}
/**
* @return Carbon
*/
@@ -268,6 +180,114 @@ class GenericRequest extends FormRequest
return $this->tags;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
// this is cheating, but it works to initialize the collections.
$this->accounts = new Collection();
$this->budgets = new Collection();
$this->categories = new Collection();
$this->bills = new Collection();
$this->tags = new Collection();
return [
'start' => 'required|date',
'end' => 'required|date|after_or_equal:start',
];
}
/**
*
*/
private function parseAccounts(): void
{
if (0 !== $this->accounts->count()) {
return;
}
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('accounts');
if (is_array($array)) {
foreach ($array as $accountId) {
$accountId = (int)$accountId;
$account = $repository->find($accountId);
if (null !== $account) {
$this->accounts->push($account);
}
}
}
}
/**
*
*/
private function parseBills(): void
{
if (0 !== $this->bills->count()) {
return;
}
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('bills');
if (is_array($array)) {
foreach ($array as $billId) {
$billId = (int)$billId;
$bill = $repository->find($billId);
if (null !== $bill) {
$this->bills->push($bill);
}
}
}
}
/**
*
*/
private function parseBudgets(): void
{
if (0 !== $this->budgets->count()) {
return;
}
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('budgets');
if (is_array($array)) {
foreach ($array as $budgetId) {
$budgetId = (int)$budgetId;
$budget = $repository->find($budgetId);
if (null !== $budget) {
$this->budgets->push($budget);
}
}
}
}
/**
*
*/
private function parseCategories(): void
{
if (0 !== $this->categories->count()) {
return;
}
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('categories');
if (is_array($array)) {
foreach ($array as $categoryId) {
$categoryId = (int)$categoryId;
$category = $repository->find($categoryId);
if (null !== $category) {
$this->categories->push($category);
}
}
}
}
/**
*
*/
@@ -289,24 +309,4 @@ class GenericRequest extends FormRequest
}
}
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
// this is cheating, but it works to initialize the collections.
$this->accounts = new Collection();
$this->budgets = new Collection();
$this->categories = new Collection();
$this->bills = new Collection();
$this->tags = new Collection();
return [
'start' => 'required|date',
'end' => 'required|date|after_or_equal:start',
];
}
}

View File

@@ -33,7 +33,6 @@ use FireflyIII\Support\Request\AppendsLocationData;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
/**
* Class UpdateRequest
@@ -63,9 +62,9 @@ class UpdateRequest extends FormRequest
'account_role' => ['account_role', 'convertString'],
'liability_type' => ['liability_type', 'convertString'],
'opening_balance' => ['opening_balance', 'convertString'],
'opening_balance_date' => ['opening_balance_date', 'date'],
'opening_balance_date' => ['opening_balance_date', 'convertDateTime'],
'cc_type' => ['credit_card_type', 'convertString'],
'cc_monthly_payment_date' => ['monthly_payment_date', 'convertString'],
'cc_monthly_payment_date' => ['monthly_payment_date', 'convertDateTime'],
'notes' => ['notes', 'stringWithNewlines'],
'interest' => ['interest', 'convertString'],
'interest_period' => ['interest_period', 'convertString'],
@@ -77,6 +76,7 @@ class UpdateRequest extends FormRequest
'liability_start_date' => ['liability_start_date', 'date'],
];
$data = $this->getAllData($fields);
return $this->appendLocationData($data, null);
}

View File

@@ -28,8 +28,8 @@ use FireflyIII\Rules\IsBoolean;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class StoreRequest
@@ -105,8 +105,8 @@ class StoreRequest extends FormRequest
$validator->after(
static function (Validator $validator) {
$data = $validator->getData();
$min = $data['amount_min'] ?? '0';
$max = $data['amount_max'] ?? '0';
$min = (string)($data['amount_min'] ?? '0');
$max = (string)($data['amount_max'] ?? '0');
if (1 === bccomp($min, $max)) {
$validator->errors()->add('amount_min', (string)trans('validation.amount_min_over_max'));

View File

@@ -79,9 +79,9 @@ class StoreRequest extends FormRequest
'currency_code' => 'exists:transaction_currencies,code',
'notes' => 'nullable|between:1,65536',
// auto budget info
'auto_budget_type' => 'in:reset,rollover,none',
'auto_budget_amount' => 'numeric|min:0|max:1000000000|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover',
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover',
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
'auto_budget_amount' => 'numeric|min:0|max:1000000000|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover|required_if:auto_budget_type,adjusted',
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover|required_if:auto_budget_type,adjusted',
];
}

View File

@@ -67,6 +67,7 @@ class UpdateRequest extends FormRequest
'none' => 0,
'reset' => 1,
'rollover' => 2,
'adjusted' => 3,
];
$allData['auto_budget_type'] = $types[$allData['auto_budget_type']] ?? 0;
}
@@ -88,7 +89,7 @@ class UpdateRequest extends FormRequest
'name' => sprintf('between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id),
'active' => [new IsBoolean()],
'notes' => 'nullable|between:1,65536',
'auto_budget_type' => 'in:reset,rollover,none',
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_currency_code' => 'exists:transaction_currencies,code',
'auto_budget_amount' => 'min:0|max:1000000000',

View File

@@ -52,8 +52,8 @@ class UpdateRequest extends FormRequest
'account_id' => ['account_id', 'convertInteger'],
'targetamount' => ['target_amount', 'convertString'],
'current_amount' => ['current_amount', 'convertString'],
'startdate' => ['start_date', 'date'],
'targetdate' => ['target_date', 'convertString'],
'startdate' => ['start_date', 'convertDateTime'],
'targetdate' => ['target_date', 'convertDateTime'],
'notes' => ['notes', 'stringWithNewlines'],
'order' => ['order', 'convertInteger'],
'object_group_title' => ['object_group_title', 'convertString'],

View File

@@ -57,8 +57,8 @@ class StoreRequest extends FormRequest
'type' => ['type', 'convertString'],
'title' => ['title', 'convertString'],
'description' => ['description', 'convertString'],
'first_date' => ['first_date', 'date'],
'repeat_until' => ['repeat_until', 'date'],
'first_date' => ['first_date', 'convertDateTime'],
'repeat_until' => ['repeat_until', 'convertDateTime'],
'nr_of_repetitions' => ['nr_of_repetitions', 'convertInteger'],
'apply_rules' => ['apply_rules', 'boolean'],
'active' => ['active', 'boolean'],
@@ -73,65 +73,6 @@ class StoreRequest extends FormRequest
];
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return [];
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array
*/
private function getRepetitionData(): array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return [];
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = $repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@@ -198,4 +139,63 @@ class StoreRequest extends FormRequest
}
);
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array
*/
private function getRepetitionData(): array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return [];
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = $repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return [];
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
}

View File

@@ -58,8 +58,8 @@ class UpdateRequest extends FormRequest
$fields = [
'title' => ['title', 'convertString'],
'description' => ['description', 'convertString'],
'first_date' => ['first_date', 'date'],
'repeat_until' => ['repeat_until', 'date'],
'first_date' => ['first_date', 'convertDateTime'],
'repeat_until' => ['repeat_until', 'convertDateTime'],
'nr_of_repetitions' => ['nr_of_repetitions', 'convertInteger'],
'apply_rules' => ['apply_rules', 'boolean'],
'active' => ['active', 'boolean'],
@@ -80,70 +80,6 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array|null
*/
private function getRepetitionData(): ?array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return null;
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = (string)$repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
if (0 === count($return)) {
return null;
}
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array|null
*/
private function getTransactionData(): ?array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@@ -205,6 +141,11 @@ class UpdateRequest extends FormRequest
function (Validator $validator) {
//$this->validateOneRecurrenceTransaction($validator);
//$this->validateOneRepetitionUpdate($validator);
/** @var Recurrence $recurrence */
$recurrence = $this->route()->parameter('recurrence');
$this->validateTransactionId($recurrence, $validator);
$this->validateRecurrenceRepetition($validator);
$this->validateRepetitionMoment($validator);
$this->validateForeignCurrencyInformation($validator);
@@ -212,4 +153,69 @@ class UpdateRequest extends FormRequest
}
);
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array|null
*/
private function getRepetitionData(): ?array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return null;
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = (string)$repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
if (0 === count($return)) {
return null;
}
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array|null
*/
private function getTransactionData(): ?array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
}

View File

@@ -67,48 +67,6 @@ class StoreRequest extends FormRequest
return $data;
}
/**
* @return array
*/
private function getRuleTriggers(): array
{
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* @return array
*/
private function getRuleActions(): array
{
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@@ -162,21 +120,6 @@ class StoreRequest extends FormRequest
);
}
/**
* Adds an error to the validator when there are no triggers in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$triggers = $data['triggers'] ?? [];
// need at least one trigger
if (!is_countable($triggers) || 0 === count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
@@ -192,6 +135,35 @@ class StoreRequest extends FormRequest
}
}
/**
* Adds an error to the validator when there are no ACTIVE actions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneActiveAction(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
// need at least one trigger
if (!is_countable($actions) || 0 === count($actions)) {
return;
}
$allInactive = true;
$inactiveIndex = 0;
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
}
}
/**
* Adds an error to the validator when there are no ACTIVE triggers in the array of data.
*
@@ -222,31 +194,59 @@ class StoreRequest extends FormRequest
}
/**
* Adds an error to the validator when there are no ACTIVE actions in the array of data.
* Adds an error to the validator when there are no triggers in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneActiveAction(Validator $validator): void
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
$data = $validator->getData();
$triggers = $data['triggers'] ?? [];
// need at least one trigger
if (!is_countable($actions) || 0 === count($actions)) {
return;
}
$allInactive = true;
$inactiveIndex = 0;
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
if (!is_countable($triggers) || 0 === count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
}
}
/**
* @return array
*/
private function getRuleActions(): array
{
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* @return array
*/
private function getRuleTriggers(): array
{
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
}

View File

@@ -52,11 +52,24 @@ class TestRequest extends FormRequest
}
/**
* @return int
* @return array
*/
private function getPage(): int
public function rules(): array
{
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page');
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'accounts' => '',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
];
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts');
}
/**
@@ -70,23 +83,10 @@ class TestRequest extends FormRequest
}
/**
* @return array
* @return int
*/
private function getAccounts(): array
private function getPage(): int
{
return $this->get('accounts');
}
/**
* @return array
*/
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'accounts' => '',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
];
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page');
}
}

View File

@@ -49,24 +49,6 @@ class TriggerRequest extends FormRequest
];
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts') ?? [];
}
/**
* @return array
*/
@@ -79,4 +61,22 @@ class TriggerRequest extends FormRequest
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
];
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts') ?? [];
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
}
}

View File

@@ -73,56 +73,6 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* @return array|null
*/
private function getRuleTriggers(): ?array
{
if (!$this->has('triggers')) {
return null;
}
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $active,
'stop_processing' => $stopProcessing,
];
}
}
return $return;
}
/**
* @return array|null
*/
private function getRuleActions(): ?array
{
if (!$this->has('actions')) {
return null;
}
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@@ -180,6 +130,21 @@ class UpdateRequest extends FormRequest
);
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneAction(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? null;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
@@ -195,6 +160,36 @@ class UpdateRequest extends FormRequest
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneValidAction(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
$allInactive = true;
$inactiveIndex = 0;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
return;
}
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
@@ -225,47 +220,52 @@ class UpdateRequest extends FormRequest
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
* @return array|null
*/
protected function atLeastOneAction(Validator $validator): void
private function getRuleActions(): ?array
{
$data = $validator->getData();
$actions = $data['actions'] ?? null;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
if (!$this->has('actions')) {
return null;
}
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
* @return array|null
*/
protected function atLeastOneValidAction(Validator $validator): void
private function getRuleTriggers(): ?array
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
$allInactive = true;
$inactiveIndex = 0;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
return;
if (!$this->has('triggers')) {
return null;
}
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $active,
'stop_processing' => $stopProcessing,
];
}
}
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
}
return $return;
}
}

View File

@@ -49,24 +49,6 @@ class TestRequest extends FormRequest
];
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts');
}
/**
* @return array
*/
@@ -79,4 +61,22 @@ class TestRequest extends FormRequest
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
];
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts');
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
}
}

View File

@@ -50,13 +50,14 @@ class TriggerRequest extends FormRequest
}
/**
* @param string $field
*
* @return Carbon|null
* @return array
*/
private function getDate(string $field): ?Carbon
public function rules(): array
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
];
}
/**
@@ -68,13 +69,12 @@ class TriggerRequest extends FormRequest
}
/**
* @return array
* @param string $field
*
* @return Carbon|null
*/
public function rules(): array
private function getDate(string $field): ?Carbon
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
];
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
}
}

View File

@@ -35,8 +35,8 @@ use FireflyIII\Validation\CurrencyValidation;
use FireflyIII\Validation\GroupValidation;
use FireflyIII\Validation\TransactionValidation;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class StoreRequest
@@ -69,103 +69,6 @@ class StoreRequest extends FormRequest
// TODO include location and ability to process it.
}
/**
* Get transaction data.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
/**
* @var array $transaction
*/
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
'type' => $this->clearString($object['type'], false),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
'currency_code' => $this->clearString((string)$object['currency_code'], false),
// foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
// amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string)$object['amount'], false),
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
// description.
'description' => $this->clearString($object['description'], false),
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']),
'source_name' => $this->clearString((string)$object['source_name'], false),
'source_iban' => $this->clearString((string)$object['source_iban'], false),
'source_number' => $this->clearString((string)$object['source_number'], false),
'source_bic' => $this->clearString((string)$object['source_bic'], false),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name'], false),
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
'destination_number' => $this->clearString((string)$object['destination_number'], false),
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
// budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
'budget_name' => $this->clearString((string)$object['budget_name'], false),
// category info
'category_id' => $this->integerFromValue((string)$object['category_id']),
'category_name' => $this->clearString((string)$object['category_name'], false),
// journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
'bill_name' => $this->clearString((string)$object['bill_name'], false),
// piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
// some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
'notes' => $this->clearString((string)$object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
// all custom fields:
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
'external_id' => $this->clearString((string)$object['external_id'], false),
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
'external_url' => $this->clearString((string)$object['external_url'], false),
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
// custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
];
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@@ -294,4 +197,101 @@ class StoreRequest extends FormRequest
}
);
}
/**
* Get transaction data.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
/**
* @var array $transaction
*/
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
'type' => $this->clearString($object['type'], false),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
'currency_code' => $this->clearString((string)$object['currency_code'], false),
// foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
// amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string)$object['amount'], false),
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
// description.
'description' => $this->clearString($object['description'], false),
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']),
'source_name' => $this->clearString((string)$object['source_name'], false),
'source_iban' => $this->clearString((string)$object['source_iban'], false),
'source_number' => $this->clearString((string)$object['source_number'], false),
'source_bic' => $this->clearString((string)$object['source_bic'], false),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name'], false),
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
'destination_number' => $this->clearString((string)$object['destination_number'], false),
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
// budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
'budget_name' => $this->clearString((string)$object['budget_name'], false),
// category info
'category_id' => $this->integerFromValue((string)$object['category_id']),
'category_name' => $this->clearString((string)$object['category_name'], false),
// journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
'bill_name' => $this->clearString((string)$object['bill_name'], false),
// piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
// some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
'notes' => $this->clearString((string)$object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
// all custom fields:
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
'external_id' => $this->clearString((string)$object['external_id'], false),
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
'external_url' => $this->clearString((string)$object['external_url'], false),
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
// custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
];
}
return $return;
}
}

View File

@@ -62,7 +62,6 @@ class UpdateRequest extends FormRequest
*/
public function getAll(): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
$this->integerFields = [
'order',
@@ -165,7 +164,7 @@ class UpdateRequest extends FormRequest
/** @var array $transaction */
foreach ($this->get('transactions') as $transaction) {
if(!is_array($transaction)) {
if (!is_array($transaction)) {
throw new FireflyException('Invalid data submitted: transaction is not array.');
}
// default response is to update nothing in the transaction:
@@ -292,6 +291,7 @@ class UpdateRequest extends FormRequest
/**
* @param array $current
* @param array $transaction
*
* @return array
*/
private function getFloatData(array $current, array $transaction): array
@@ -300,7 +300,7 @@ class UpdateRequest extends FormRequest
if (array_key_exists($fieldName, $transaction)) {
$value = $transaction[$fieldName];
if (is_float($value)) {
$current[$fieldName] = sprintf('%.24f', $value);
$current[$fieldName] = sprintf('%.12f', $value);
}
if (!is_float($value)) {
$current[$fieldName] = (string)$value;
@@ -319,6 +319,7 @@ class UpdateRequest extends FormRequest
public function rules(): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
return [
// basic fields for group:
'group_title' => 'between:1,1000',

View File

@@ -64,9 +64,9 @@ class UpdateRequest extends FormRequest
$linkType = $this->route()->parameter('linkType');
return [
'name' => [Rule::unique('link_types', 'name')->ignore($linkType->id), 'min:1','max:1024'],
'outward' => ['different:inward', Rule::unique('link_types', 'outward')->ignore($linkType->id), 'min:1','max:1024'],
'inward' => ['different:outward', Rule::unique('link_types', 'inward')->ignore($linkType->id), 'min:1','max:1024'],
'name' => [Rule::unique('link_types', 'name')->ignore($linkType->id), 'min:1', 'max:1024'],
'outward' => ['different:inward', Rule::unique('link_types', 'outward')->ignore($linkType->id), 'min:1', 'max:1024'],
'inward' => ['different:outward', Rule::unique('link_types', 'inward')->ignore($linkType->id), 'min:1', 'max:1024'],
];
}
}

View File

@@ -29,8 +29,8 @@ use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -43,9 +43,9 @@ class AccountController extends Controller
{
use AccountFilter;
private array $balanceTypes;
private AdminAccountRepositoryInterface $adminRepository;
private AccountRepositoryInterface $repository;
private array $balanceTypes;
private AccountRepositoryInterface $repository;
/**
* AccountController constructor.
@@ -55,9 +55,7 @@ class AccountController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(AccountRepositoryInterface::class);
$this->repository = app(AccountRepositoryInterface::class);
$this->adminRepository = app(AdminAccountRepositoryInterface::class);
return $next($request);
@@ -113,10 +111,10 @@ class AccountController extends Controller
}
// custom order.
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
usort(
$return,
function ($a, $b) use ($order) {
function ($a, $b) {
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
$pos_a = array_search($a['type'], $order, true);
$pos_b = array_search($b['type'], $order, true);

View File

@@ -53,6 +53,7 @@ class AccountController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
return $next($request);
}
);
@@ -63,6 +64,7 @@ class AccountController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/charts/getChartAccountOverview
*
* @param DateRequest $request
*
* @return JsonResponse
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface

View File

@@ -64,6 +64,54 @@ class Controller extends BaseController
}
}
/**
* @param string $key
* @param LengthAwarePaginator $paginator
* @param AbstractTransformer $transformer
*
* @return array
*/
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
{
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$objects = $paginator->getCollection();
// the transformer, at this point, needs to collect information that ALL items in the collection
// require, like meta data and stuff like that, and save it for later.
$transformer->collectMetaData($objects);
$resource = new FractalCollection($objects, $transformer, $key);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return $manager->createData($resource)->toArray();
}
/**
* Returns a JSON API object and returns it.
*
* @param string $key
* @param Model $object
* @param AbstractTransformer $transformer
*
* @return array
*/
final protected function jsonApiObject(string $key, Model $object, AbstractTransformer $transformer): array
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$transformer->collectMetaData(new Collection([$object]));
$resource = new Item($object, $transformer, $key);
return $manager->createData($resource)->toArray();
}
/**
* TODO duplicate from V1 controller
* Method to grab all parameters from the URL.
@@ -131,49 +179,4 @@ class Controller extends BaseController
return $bag;
}
/**
* @param string $key
* @param LengthAwarePaginator $paginator
* @param AbstractTransformer $transformer
* @return array
*/
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
{
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$objects = $paginator->getCollection();
// the transformer, at this point, needs to collect information that ALL items in the collection
// require, like meta data and stuff like that, and save it for later.
$transformer->collectMetaData($objects);
$resource = new FractalCollection($objects, $transformer, $key);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return $manager->createData($resource)->toArray();
}
/**
* Returns a JSON API object and returns it.
*
* @param string $key
* @param Model $object
* @param AbstractTransformer $transformer
* @return array
*/
final protected function jsonApiObject(string $key, Model $object, AbstractTransformer $transformer): array
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$transformer->collectMetaData(new Collection([$object]));
$resource = new Item($object, $transformer, $key);
return $manager->createData($resource)->toArray();
}
}

View File

@@ -48,6 +48,7 @@ class SumController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BillRepositoryInterface::class);
return $next($request);
}
);
@@ -58,6 +59,7 @@ class SumController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/transactions-sum/getBillsPaidTrSum
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function paid(DateRequest $request): JsonResponse
@@ -75,6 +77,7 @@ class SumController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/transactions-sum/getBillsUnpaidTrSum
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function unpaid(DateRequest $request): JsonResponse

View File

@@ -41,6 +41,7 @@ class ListController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);
}
);
@@ -51,6 +52,7 @@ class ListController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/budgets/listBudgets
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
@@ -61,6 +63,7 @@ class ListController extends Controller
$paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page'));
$transformer = new BudgetTransformer();
return response()
->api($this->jsonApiList('budgets', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -48,6 +48,7 @@ class ShowController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);
}
);

View File

@@ -48,6 +48,7 @@ class SumController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);
}
);
@@ -58,6 +59,7 @@ class SumController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/budgets/getBudgetedForBudget
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function budgeted(DateRequest $request): JsonResponse
@@ -72,7 +74,9 @@ class SumController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/budgets/getSpentForBudget
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function spent(DateRequest $request): JsonResponse

View File

@@ -42,6 +42,7 @@ class ListController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetLimitRepositoryInterface::class);
return $next($request);
}
);
@@ -60,6 +61,7 @@ class ListController extends Controller
$paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page'));
$transformer = new BudgetLimitTransformer();
return response()
->api($this->jsonApiList('budget_limits', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -48,6 +48,7 @@ class NetWorthController extends Controller
function ($request, $next) {
$this->netWorth = app(NetWorthInterface::class);
$this->netWorth->setUser(auth()->user());
return $next($request);
}
);
@@ -56,7 +57,9 @@ class NetWorthController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/net-worth/getNetWorth
*
* @param SingleDateRequest $request
*
* @return JsonResponse
*/
public function get(SingleDateRequest $request): JsonResponse

View File

@@ -37,7 +37,9 @@ class PreferencesController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/preferences/getPreference
*
* @param Preference $preference
*
* @return JsonResponse
*/
public function get(Preference $preference): JsonResponse

View File

@@ -46,6 +46,7 @@ class AccountController extends Controller
*
* @param ListRequest $request
* @param Account $account
*
* @return JsonResponse
*/
public function listTransactions(ListRequest $request, Account $account): JsonResponse

View File

@@ -60,6 +60,7 @@ class AutocompleteRequest extends FormRequest
$array = array_diff($array, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION]);
/** @var User $user */
$user = auth()->user();
return [
'types' => $array,
'query' => $this->convertString('query'),

View File

@@ -25,12 +25,14 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Response\Sum;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
/**
* Class AutoSum
*
* @deprecated
*/
class AutoSum
@@ -39,7 +41,9 @@ class AutoSum
* @param Collection $objects
* @param Closure $getCurrency
* @param Closure $getSum
*
* @return array
* @throws FireflyException
*/
public function autoSum(Collection $objects, Closure $getCurrency, Closure $getSum): array
{
@@ -64,6 +68,6 @@ class AutoSum
}
var_dump(array_values($return));
exit;
throw new FireflyException('Not implemented');
}
}

View File

@@ -39,22 +39,10 @@ use Illuminate\Console\Command;
*/
class CorrectAmounts extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command makes sure positive and negative amounts are recorded correctly.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-amount-pos-neg';
protected $signature = 'firefly-iii:fix-amount-pos-neg';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
@@ -91,6 +79,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All auto budget amounts are positive.');
return;
}
/** @var AutoBudget $item */
@@ -110,6 +99,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All available budget amounts are positive.');
return;
}
/** @var AvailableBudget $item */
@@ -129,6 +119,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All bill amounts are positive.');
return;
}
/** @var Bill $item */
@@ -148,6 +139,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All budget limit amounts are positive.');
return;
}
/** @var BudgetLimit $item */
@@ -167,6 +159,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All currency exchange rates are positive.');
return;
}
/** @var BudgetLimit $item */
@@ -177,25 +170,6 @@ class CorrectAmounts extends Command
$this->line(sprintf('Corrected %d currency exchange rate(s).', $count));
}
/**
* @return void
*/
private function fixRepetitions(): void
{
$set = PiggyBankRepetition::where('currentamount', '<', 0)->get();
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All piggy bank repetition amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
foreach ($set as $item) {
$item->currentamount = app('steam')->positive((string)$item->currentamount);
$item->save();
}
$this->line(sprintf('Corrected %d piggy bank repetition amount(s).', $count));
}
/**
* @return void
*/
@@ -205,6 +179,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All piggy bank amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
@@ -226,6 +201,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All recurring transaction amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
@@ -237,6 +213,26 @@ class CorrectAmounts extends Command
$this->line(sprintf('Corrected %d recurring transaction amount(s).', $count));
}
/**
* @return void
*/
private function fixRepetitions(): void
{
$set = PiggyBankRepetition::where('currentamount', '<', 0)->get();
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All piggy bank repetition amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
foreach ($set as $item) {
$item->currentamount = app('steam')->positive((string)$item->currentamount);
$item->save();
}
$this->line(sprintf('Corrected %d piggy bank repetition amount(s).', $count));
}
/**
* @return void
*/
@@ -255,6 +251,7 @@ class CorrectAmounts extends Command
}
if (0 === $fixed) {
$this->info('Correct: All rule trigger amounts are positive.');
return;
}
$this->line(sprintf('Corrected %d rule trigger amount(s).', $fixed));

View File

@@ -34,28 +34,18 @@ use Schema;
*/
class CorrectDatabase extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Will correct the integrity of your database, if necessary.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:correct-database';
protected $signature = 'firefly-iii:correct-database';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->line('Handle Firefly III database correction commands.');
// if table does not exist, return false
if (!Schema::hasTable('users')) {
$this->error('No "users"-table, will not continue.');
return 1;
}
$commands = [
@@ -83,7 +73,7 @@ class CorrectDatabase extends Command
'firefly-iii:fix-frontpage-accounts',
// new!
'firefly-iii:unify-group-accounts',
'firefly-iii:trigger-credit-recalculation'
'firefly-iii:trigger-credit-recalculation',
];
foreach ($commands as $command) {
$this->line(sprintf('Now executing command "%s"', $command));

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
@@ -33,26 +32,15 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Console\Command;
use JsonException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Collection;
/**
* Class CorrectOpeningBalanceCurrencies
*/
class CorrectOpeningBalanceCurrencies extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Will make sure that opening balance transaction currencies match the account they\'re for.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-ob-currencies';
protected $signature = 'firefly-iii:fix-ob-currencies';
/**
* Execute the console command.
@@ -61,32 +49,22 @@ class CorrectOpeningBalanceCurrencies extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Now in %s', __METHOD__));
// get all OB journals:
$set = TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereNull('transaction_journals.deleted_at')
->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*']);
$this->line(sprintf('Going to verify %d opening balance transactions.', $set->count()));
$count = 0;
$journals = $this->getJournals();
$count = 0;
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
foreach ($journals as $journal) {
$count += $this->correctJournal($journal);
}
if ($count > 0) {
$message = sprintf('Corrected %d opening balance transaction(s).', $count);
Log::debug($message);
$this->line($message);
}
if (0 === $count) {
$message = 'There was nothing to fix in the opening balance transactions.';
Log::debug($message);
$message = 'Correct: There was nothing to fix in the opening balance transactions.';
$this->info($message);
}
Log::debug(sprintf('Done with %s', __METHOD__));
return 0;
}
@@ -94,24 +72,21 @@ class CorrectOpeningBalanceCurrencies extends Command
* @param TransactionJournal $journal
*
* @return int
* @throws FireflyException
* @throws JsonException
*/
private function correctJournal(TransactionJournal $journal): int
{
// get the asset account for this opening balance:
$account = $this->getAccount($journal);
if (null === $account) {
$message = sprintf('Transaction journal #%d has no valid account. Cant fix this line.', $journal->id);
$message = sprintf('Transaction journal #%d has no valid account. Can\'t fix this line.', $journal->id);
app('log')->warning($message);
$this->warn($message);
return 0;
}
$currency = $this->getCurrency($account);
// update journal and all transactions:
return $this->setCurrency($journal, $currency);
return $this->setCorrectCurrency($account, $journal);
}
/**
@@ -130,6 +105,7 @@ class CorrectOpeningBalanceCurrencies extends Command
return $account;
}
}
return null;
}
@@ -137,8 +113,6 @@ class CorrectOpeningBalanceCurrencies extends Command
* @param Account $account
*
* @return TransactionCurrency
* @throws JsonException
* @throws FireflyException
*/
private function getCurrency(Account $account): TransactionCurrency
{
@@ -150,14 +124,25 @@ class CorrectOpeningBalanceCurrencies extends Command
}
/**
* @return Collection
*/
private function getJournals(): Collection
{
/** @var Collection */
return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereNull('transaction_journals.deleted_at')
->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*']);
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param TransactionCurrency $currency
*
* @return int
*/
private function setCurrency(TransactionJournal $journal, TransactionCurrency $currency): int
private function setCorrectCurrency(Account $account, TransactionJournal $journal): int
{
$count = 0;
$currency = $this->getCurrency($account);
$count = 0;
if ((int)$journal->transaction_currency_id !== (int)$currency->id) {
$journal->transaction_currency_id = $currency->id;
$journal->save();

View File

@@ -58,7 +58,6 @@ class CreateAccessTokens extends Command
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
$start = microtime(true);
$count = 0;
$users = $repository->all();
/** @var User $user */
@@ -72,10 +71,8 @@ class CreateAccessTokens extends Command
}
}
if (0 === $count) {
$this->info('All access tokens OK!');
$this->info('Correct: Verified access tokens.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verify access tokens in %s seconds.', $end));
return 0;
}

View File

@@ -51,7 +51,6 @@ class CreateLinkTypes extends Command
*/
public function handle(): int
{
$start = microtime(true);
$count = 0;
$set = [
'Related' => ['relates to', 'relates to'],
@@ -74,11 +73,8 @@ class CreateLinkTypes extends Command
$link->save();
}
if (0 === $count) {
$this->info('All link types OK!');
$this->info('Correct: all link types are OK');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified link types in %s seconds', $end));
return 0;
}
}

View File

@@ -26,25 +26,14 @@ namespace FireflyIII\Console\Commands\Correction;
use Exception;
use FireflyIII\Models\TransactionGroup;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* Class DeleteEmptyGroups
*/
class DeleteEmptyGroups extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete empty transaction groups.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:delete-empty-groups';
protected $signature = 'firefly-iii:delete-empty-groups';
/**
* Execute the console command.
@@ -55,14 +44,11 @@ class DeleteEmptyGroups extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Now in %s', __METHOD__));
$start = microtime(true);
$groupIds
= TransactionGroup::leftJoin('transaction_journals', 'transaction_groups.id', '=', 'transaction_journals.transaction_group_id')
->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray();
= TransactionGroup::leftJoin('transaction_journals', 'transaction_groups.id', '=', 'transaction_journals.transaction_group_id')
->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray();
$total = count($groupIds);
Log::debug(sprintf('Count is %d', $total));
if ($total > 0) {
$this->info(sprintf('Deleted %d empty transaction group(s).', $total));
@@ -72,8 +58,9 @@ class DeleteEmptyGroups extends Command
TransactionGroup::whereNull('deleted_at')->whereIn('id', $chunk)->delete();
}
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified empty groups in %s seconds', $end));
if (0 === $total) {
$this->info('Correct: verified empty groups.');
}
return 0;
}

View File

@@ -61,6 +61,30 @@ class DeleteEmptyJournals extends Command
return 0;
}
private function deleteEmptyJournals(): void
{
$count = 0;
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->groupBy('transaction_journals.id')
->whereNull('transactions.transaction_journal_id')
->get(['transaction_journals.id']);
foreach ($set as $entry) {
try {
TransactionJournal::find($entry->id)->delete();
} catch (QueryException $e) {
Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
}
$this->info(sprintf('Deleted empty transaction journal #%d', $entry->id));
++$count;
}
if (0 === $count) {
$this->info('Correct: no empty transaction journals.');
}
}
/**
* Delete transactions and their journals if they have an uneven number of transactions.
*/
@@ -88,34 +112,7 @@ class DeleteEmptyJournals extends Command
}
}
if (0 === $total) {
$this->info('No uneven transaction journals.');
$this->info('Correct: no uneven transaction journals.');
}
}
private function deleteEmptyJournals(): void
{
$start = microtime(true);
$count = 0;
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->groupBy('transaction_journals.id')
->whereNull('transactions.transaction_journal_id')
->get(['transaction_journals.id']);
foreach ($set as $entry) {
try {
TransactionJournal::find($entry->id)->delete();
} catch (QueryException $e) {
Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
}
$this->info(sprintf('Deleted empty transaction journal #%d', $entry->id));
++$count;
}
if (0 === $count) {
$this->info('No empty transaction journals.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified empty journals in %s seconds', $end));
}
}

View File

@@ -27,7 +27,6 @@ use Exception;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use stdClass;
/**
@@ -56,16 +55,45 @@ class DeleteOrphanedTransactions extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->deleteOrphanedJournals();
$this->deleteOrphanedTransactions();
$this->deleteFromOrphanedAccounts();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified orphans in %s seconds', $end));
return 0;
}
/**
*
*/
private function deleteFromOrphanedAccounts(): void
{
$set
= Transaction::leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
->whereNotNull('accounts.deleted_at')
->get(['transactions.*']);
$count = 0;
/** @var Transaction $transaction */
foreach ($set as $transaction) {
// delete journals
$journal = TransactionJournal::find((int)$transaction->transaction_journal_id);
if ($journal) {
$journal->delete();
}
Transaction::where('transaction_journal_id', (int)$transaction->transaction_journal_id)->delete();
$this->line(
sprintf(
'Deleted transaction journal #%d because account #%d was already deleted.',
$transaction->transaction_journal_id,
$transaction->account_id
)
);
$count++;
}
if (0 === $count) {
$this->info('Correct: no orphaned accounts.');
}
}
private function deleteOrphanedJournals(): void
{
$set = TransactionJournal::leftJoin('transaction_groups', 'transaction_journals.transaction_group_id', 'transaction_groups.id')
@@ -74,7 +102,7 @@ class DeleteOrphanedTransactions extends Command
->get(['transaction_journals.id', 'transaction_journals.transaction_group_id']);
$count = $set->count();
if (0 === $count) {
$this->info('No orphaned journals.');
$this->info('Correct: no orphaned journals.');
}
if ($count > 0) {
$this->info(sprintf('Found %d orphaned journal(s).', $count));
@@ -126,39 +154,7 @@ class DeleteOrphanedTransactions extends Command
}
}
if (0 === $count) {
$this->info('No orphaned transactions.');
}
}
/**
*
*/
private function deleteFromOrphanedAccounts(): void
{
$set
= Transaction::leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
->whereNotNull('accounts.deleted_at')
->get(['transactions.*']);
$count = 0;
/** @var Transaction $transaction */
foreach ($set as $transaction) {
// delete journals
$journal = TransactionJournal::find((int)$transaction->transaction_journal_id);
if ($journal) {
$journal->delete();
}
Transaction::where('transaction_journal_id', (int)$transaction->transaction_journal_id)->delete();
$this->line(
sprintf(
'Deleted transaction journal #%d because account #%d was already deleted.',
$transaction->transaction_journal_id,
$transaction->account_id
)
);
$count++;
}
if (0 === $count) {
$this->info('No orphaned accounts.');
$this->info('Correct: no orphaned transactions.');
}
}
}

View File

@@ -52,7 +52,6 @@ class DeleteZeroAmount extends Command
*/
public function handle(): int
{
$start = microtime(true);
$set = Transaction::where('amount', 0)->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
$set = array_unique($set);
$journals = TransactionJournal::whereIn('id', $set)->get();
@@ -64,12 +63,9 @@ class DeleteZeroAmount extends Command
Transaction::where('transaction_journal_id', $journal->id)->delete();
}
if (0 === $journals->count()) {
$this->info('No zero-amount transaction journals.');
$this->info('Correct: no zero-amount transaction journals.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified zero-amount integrity in %s seconds', $end));
return 0;
}
}

View File

@@ -37,18 +37,8 @@ use Illuminate\Support\Facades\Log;
*/
class EnableCurrencies extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Enables all currencies in use.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:enable-currencies';
protected $signature = 'firefly-iii:enable-currencies';
/**
* Execute the console command.
@@ -57,7 +47,6 @@ class EnableCurrencies extends Command
*/
public function handle(): int
{
$start = microtime(true);
$found = [];
// get all meta entries
/** @var Collection $meta */
@@ -85,8 +74,8 @@ class EnableCurrencies extends Command
$found[] = (int)$entry->transaction_currency_id;
}
$found = array_values(array_unique($found));
$found = array_values(
$found = array_values(array_unique($found));
$found = array_values(
array_filter(
$found,
function (int $currencyId) {
@@ -94,22 +83,15 @@ class EnableCurrencies extends Command
}
)
);
$message = sprintf('%d different currencies are currently in use.', count($found));
$this->info($message);
Log::debug($message, $found);
$disabled = TransactionCurrency::whereIn('id', $found)->where('enabled', false)->count();
if ($disabled > 0) {
$this->info(sprintf('%d were (was) still disabled. This has been corrected.', $disabled));
}
if (0 === $disabled) {
$this->info('All currencies are correctly enabled or disabled.');
$this->info('Correct: All currencies are correctly enabled or disabled.');
}
TransactionCurrency::whereIn('id', $found)->update(['enabled' => true]);
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified currencies in %s seconds.', $end));
return 0;
}
}

View File

@@ -32,18 +32,8 @@ use Illuminate\Console\Command;
*/
class FixAccountOrder extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Make sure account order is correct.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-account-order';
protected $signature = 'firefly-iii:fix-account-order';
private AccountRepositoryInterface $repository;
@@ -55,7 +45,6 @@ class FixAccountOrder extends Command
public function handle(): int
{
$this->stupidLaravel();
$start = microtime(true);
$users = User::get();
foreach ($users as $user) {
@@ -63,8 +52,7 @@ class FixAccountOrder extends Command
$this->repository->resetAccountOrder();
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account order took %s seconds', $end));
$this->info('Correct: All accounts are ordered correctly');
return 0;
}

View File

@@ -38,18 +38,8 @@ use Illuminate\Support\Facades\Log;
*/
class FixAccountTypes extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Make sure all journals have the correct from/to account types.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-account-types';
protected $signature = 'firefly-iii:fix-account-types';
private int $count;
private array $expected;
private AccountFactory $factory;
@@ -63,103 +53,23 @@ class FixAccountTypes extends Command
public function handle(): int
{
$this->stupidLaravel();
Log::debug('Now in fix-account-types');
$start = microtime(true);
$this->factory = app(AccountFactory::class);
$this->expected = config('firefly.source_dests');
$journals = TransactionJournal::with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accounttype'])->get();
Log::debug(sprintf('Found %d journals to inspect.', $journals->count()));
foreach ($journals as $journal) {
$this->inspectJournal($journal);
}
if (0 === $this->count) {
Log::debug('No journals had to be fixed.');
$this->info('All account types are OK!');
$this->info('Correct: all account types are OK');
}
if (0 !== $this->count) {
Log::debug(sprintf('%d journals had to be fixed.', $this->count));
$this->info(sprintf('Acted on %d transaction(s)!', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account types took %s seconds', $end));
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
}
/**
* @param TransactionJournal $journal
*
* @throws FireflyException
*/
private function inspectJournal(TransactionJournal $journal): void
{
$transactions = $journal->transactions()->count();
if (2 !== $transactions) {
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
return;
}
$type = $journal->transactionType->type;
$sourceTransaction = $this->getSourceTransaction($journal);
$destTransaction = $this->getDestinationTransaction($journal);
$sourceAccount = $sourceTransaction->account;
$sourceAccountType = $sourceAccount->accountType->type;
$destAccount = $destTransaction->account;
$destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) {
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
return;
}
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
return;
}
$expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
}
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getSourceTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '<', 0);
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getDestinationTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '>', 0);
}
/**
* @param TransactionJournal $journal
* @param string $type
@@ -254,4 +164,77 @@ class FixAccountTypes extends Command
break;
}
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getDestinationTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '>', 0);
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getSourceTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '<', 0);
}
/**
* @param TransactionJournal $journal
*
* @throws FireflyException
*/
private function inspectJournal(TransactionJournal $journal): void
{
$transactions = $journal->transactions()->count();
if (2 !== $transactions) {
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
return;
}
$type = $journal->transactionType->type;
$sourceTransaction = $this->getSourceTransaction($journal);
$destTransaction = $this->getDestinationTransaction($journal);
$sourceAccount = $sourceTransaction->account;
$sourceAccountType = $sourceAccount->accountType->type;
$destAccount = $destTransaction->account;
$destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) {
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
return;
}
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
return;
}
$expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
}
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
}
}

View File

@@ -36,18 +36,8 @@ use Illuminate\Console\Command;
*/
class FixFrontpageAccounts extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes a preference that may include deleted accounts or accounts of another type.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-frontpage-accounts';
protected $signature = 'firefly-iii:fix-frontpage-accounts';
/**
* Execute the console command.
@@ -56,8 +46,6 @@ class FixFrontpageAccounts extends Command
*/
public function handle(): int
{
$start = microtime(true);
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
@@ -66,8 +54,7 @@ class FixFrontpageAccounts extends Command
$this->fixPreference($preference);
}
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account preferences took %s seconds', $end));
$this->info('Correct: account preferences are OK');
return 0;
}

View File

@@ -36,18 +36,8 @@ use Illuminate\Console\Command;
*/
class FixGroupAccounts extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Unify the source / destination accounts of split groups.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:unify-group-accounts';
protected $signature = 'firefly-iii:unify-group-accounts';
/**
* Execute the console command.
@@ -72,7 +62,7 @@ class FixGroupAccounts extends Command
$handler->unifyAccounts($event);
}
$this->line('Updated inconsistent transaction groups.');
$this->info('Correct: updated possible inconsistent transaction groups.');
return 0;
}

View File

@@ -34,18 +34,9 @@ use Illuminate\Support\Collection;
*/
class FixIbans extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Removes spaces from IBANs';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-ibans';
protected $signature = 'firefly-iii:fix-ibans';
private int $count = 0;
/**
* Execute the console command.
@@ -57,39 +48,56 @@ class FixIbans extends Command
$accounts = Account::whereNotNull('iban')->get();
$this->filterIbans($accounts);
$this->countAndCorrectIbans($accounts);
if (0 === $this->count) {
$this->info('Correct: All IBANs are valid.');
}
return 0;
}
/**
* @param Collection $accounts
*
* @return void
*/
private function countAndCorrectIbans(Collection $accounts): void
{
$set = [];
/** @var Account $account */
foreach($accounts as $account) {
$userId = (int)$account->user_id;
foreach ($accounts as $account) {
$userId = (int)$account->user_id;
$set[$userId] = $set[$userId] ?? [];
$iban = (string)$account->iban;
$iban = (string)$account->iban;
if ('' === $iban) {
continue;
}
$type = $account->accountType->type;
if(in_array($type, [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], true)) {
if (in_array($type, [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], true)) {
$type = 'liabilities';
}
if(array_key_exists($iban, $set[$userId])) {
if (array_key_exists($iban, $set[$userId])) {
// iban already in use! two exceptions exist:
if(
!(AccountType::EXPENSE === $set[$userId][$iban] && AccountType::REVENUE === $type) && // allowed combination
if (
!(AccountType::EXPENSE === $set[$userId][$iban] && AccountType::REVENUE === $type)
&& // allowed combination
!(AccountType::REVENUE === $set[$userId][$iban] && AccountType::EXPENSE === $type) // also allowed combination.
) {
$this->line(sprintf('IBAN "%s" is used more than once and will be removed from %s #%d ("%s")', $iban, $account->accountType->type, $account->id, $account->name));
$this->line(
sprintf(
'IBAN "%s" is used more than once and will be removed from %s #%d ("%s")',
$iban,
$account->accountType->type,
$account->id,
$account->name
)
);
$account->iban = null;
$account->save();
$this->count++;
}
}
if(!array_key_exists($iban, $set[$userId])) {
if (!array_key_exists($iban, $set[$userId])) {
$set[$userId][$iban] = $type;
}
}
@@ -97,6 +105,7 @@ class FixIbans extends Command
/**
* @param Collection $accounts
*
* @return void
*/
private function filterIbans(Collection $accounts): void
@@ -110,6 +119,7 @@ class FixIbans extends Command
$account->iban = $iban;
$account->save();
$this->line(sprintf('Removed spaces from IBAN of account #%d', $account->id));
$this->count++;
}
}
}

View File

@@ -34,18 +34,8 @@ use Illuminate\Console\Command;
class FixLongDescriptions extends Command
{
private const MAX_LENGTH = 1000;
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes long descriptions in journals and groups.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-long-descriptions';
protected $signature = 'firefly-iii:fix-long-descriptions';
/**
* Execute the console command.
@@ -54,14 +44,15 @@ class FixLongDescriptions extends Command
*/
public function handle(): int
{
$start = microtime(true);
$journals = TransactionJournal::get(['id', 'description']);
$count = 0;
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
if (strlen($journal->description) > self::MAX_LENGTH) {
$journal->description = substr($journal->description, 0, self::MAX_LENGTH);
$journal->save();
$this->line(sprintf('Truncated description of transaction journal #%d', $journal->id));
$count++;
}
}
@@ -72,11 +63,12 @@ class FixLongDescriptions extends Command
$group->title = substr($group->title, 0, self::MAX_LENGTH);
$group->save();
$this->line(sprintf('Truncated description of transaction group #%d', $group->id));
$count++;
}
}
$end = round(microtime(true) - $start, 2);
$this->info('Verified all transaction group and journal title lengths.');
$this->info(sprintf('Took %s seconds.', $end));
if (0 === $count) {
$this->info('Correct: all transaction group and journal title lengths are within bounds.');
}
return 0;
}

View File

@@ -25,28 +25,17 @@ namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Console\Command;
/**
* Report (and fix) piggy banks. Make sure there are only transfers linked to piggy bank events.
* Report (and fix) piggy banks.
*
* Class FixPiggies
*/
class FixPiggies extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes common issues with piggy banks.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-piggies';
protected $signature = 'firefly-iii:fix-piggies';
/**
* Execute the console command.
@@ -56,8 +45,7 @@ class FixPiggies extends Command
public function handle(): int
{
$count = 0;
$start = microtime(true);
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get();
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal'])->get();
/** @var PiggyBankEvent $event */
foreach ($set as $event) {
@@ -73,26 +61,14 @@ class FixPiggies extends Command
$count++;
continue;
}
$type = $journal->transactionType->type;
if (TransactionType::TRANSFER !== $type) {
$event->transaction_journal_id = null;
$event->save();
$this->line(sprintf('Piggy bank #%d was referenced by an invalid event. This has been fixed.', $event->piggy_bank_id));
$count++;
}
}
if (0 === $count) {
$this->line('All piggy bank events are correct.');
$this->info('Correct: all piggy bank events are OK.');
}
if (0 !== $count) {
$this->line(sprintf('Fixed %d piggy bank event(s).', $count));
}
$end = round(microtime(true) - $start, 2);
$this->line(sprintf('Verified the content of %d piggy bank events in %s seconds.', $set->count(), $end));
return 0;
}
}

View File

@@ -37,22 +37,11 @@ use Illuminate\Console\Command;
*/
class FixRecurringTransactions extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes recurring transactions with the wrong transaction type.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-recurring-transactions';
/** @var RecurringRepositoryInterface */
private $recurringRepos;
/** @var UserRepositoryInterface */
private $userRepos;
protected $signature = 'firefly-iii:fix-recurring-transactions';
private int $count = 0;
private RecurringRepositoryInterface $recurringRepos;
private UserRepositoryInterface $userRepos;
/**
* Execute the console command.
@@ -61,28 +50,15 @@ class FixRecurringTransactions extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->stupidLaravel();
$this->correctTransactions();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Corrected recurring transactions in %s seconds.', $end));
if (0 === $this->count) {
$this->info('Correct: all recurring transactions are OK.');
}
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->recurringRepos = app(RecurringRepositoryInterface::class);
$this->userRepos = app(UserRepositoryInterface::class);
}
/**
*
*/
@@ -95,19 +71,6 @@ class FixRecurringTransactions extends Command
}
}
/**
* @param User $user
*/
private function processUser(User $user): void
{
$this->recurringRepos->setUser($user);
$recurrences = $this->recurringRepos->get();
/** @var Recurrence $recurrence */
foreach ($recurrences as $recurrence) {
$this->processRecurrence($recurrence);
}
}
/**
* @param Recurrence $recurrence
*/
@@ -137,7 +100,34 @@ class FixRecurringTransactions extends Command
if (null !== $transactionType) {
$recurrence->transaction_type_id = $transactionType->id;
$recurrence->save();
$this->count++;
}
}
}
/**
* @param User $user
*/
private function processUser(User $user): void
{
$this->recurringRepos->setUser($user);
$recurrences = $this->recurringRepos->get();
/** @var Recurrence $recurrence */
foreach ($recurrences as $recurrence) {
$this->processRecurrence($recurrence);
}
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->recurringRepos = app(RecurringRepositoryInterface::class);
$this->userRepos = app(UserRepositoryInterface::class);
}
}

View File

@@ -37,18 +37,8 @@ use Illuminate\Support\Collection;
*/
class FixTransactionTypes extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Make sure all transactions are of the correct type, based on source + dest.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-transaction-types';
protected $signature = 'firefly-iii:fix-transaction-types';
/**
* Execute the console command.
@@ -57,7 +47,6 @@ class FixTransactionTypes extends Command
*/
public function handle(): int
{
$start = microtime(true);
$count = 0;
$journals = $this->collectJournals();
/** @var TransactionJournal $journal */
@@ -67,17 +56,29 @@ class FixTransactionTypes extends Command
$count++;
}
}
$end = round(microtime(true) - $start, 2);
if ($count > 0) {
$this->info(sprintf('Corrected transaction type of %d transaction journals in %s seconds.', $count, $end));
$this->info('Corrected transaction type of %d transaction journals.', $count);
return 0;
}
$this->line(sprintf('All transaction journals are of the correct transaction type (in %s seconds).', $end));
$this->info('Correct: all transaction journals are of the correct transaction type');
return 0;
}
/**
* @param TransactionJournal $journal
* @param string $expectedType
*/
private function changeJournal(TransactionJournal $journal, string $expectedType): void
{
$type = TransactionType::whereType($expectedType)->first();
if (null !== $type) {
$journal->transaction_type_id = $type->id;
$journal->save();
}
}
/**
* Collect all transaction journals.
*
@@ -125,36 +126,6 @@ class FixTransactionTypes extends Command
return false;
}
/**
* @param TransactionJournal $journal
*
* @return Account
* @throws FireflyException
*/
private function getSourceAccount(TransactionJournal $journal): Account
{
$collection = $journal->transactions->filter(
static function (Transaction $transaction) {
return $transaction->amount < 0;
}
);
if (0 === $collection->count()) {
throw new FireflyException(sprintf('300001: Journal #%d has no source transaction.', $journal->id));
}
if (1 !== $collection->count()) {
throw new FireflyException(sprintf('300002: Journal #%d has multiple source transactions.', $journal->id));
}
/** @var Transaction $transaction */
$transaction = $collection->first();
/** @var Account|null $account */
$account = $transaction->account;
if (null === $account) {
throw new FireflyException(sprintf('300003: Journal #%d, transaction #%d has no source account.', $journal->id, $transaction->id));
}
return $account;
}
/**
* @param TransactionJournal $journal
*
@@ -187,14 +158,31 @@ class FixTransactionTypes extends Command
/**
* @param TransactionJournal $journal
* @param string $expectedType
*
* @return Account
* @throws FireflyException
*/
private function changeJournal(TransactionJournal $journal, string $expectedType): void
private function getSourceAccount(TransactionJournal $journal): Account
{
$type = TransactionType::whereType($expectedType)->first();
if (null !== $type) {
$journal->transaction_type_id = $type->id;
$journal->save();
$collection = $journal->transactions->filter(
static function (Transaction $transaction) {
return $transaction->amount < 0;
}
);
if (0 === $collection->count()) {
throw new FireflyException(sprintf('300001: Journal #%d has no source transaction.', $journal->id));
}
if (1 !== $collection->count()) {
throw new FireflyException(sprintf('300002: Journal #%d has multiple source transactions.', $journal->id));
}
/** @var Transaction $transaction */
$transaction = $collection->first();
/** @var Account|null $account */
$account = $transaction->account;
if (null === $account) {
throw new FireflyException(sprintf('300003: Journal #%d, transaction #%d has no source account.', $journal->id, $transaction->id));
}
return $account;
}
}

View File

@@ -27,7 +27,6 @@ use DB;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use stdClass;
/**
@@ -35,18 +34,8 @@ use stdClass;
*/
class FixUnevenAmount extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fix journals with uneven amounts.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-uneven-amount';
protected $signature = 'firefly-iii:fix-uneven-amount';
/**
* Execute the console command.
@@ -55,10 +44,7 @@ class FixUnevenAmount extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Now in %s', __METHOD__));
$start = microtime(true);
$count = 0;
// get invalid journals
$count = 0;
$journals = DB::table('transactions')
->groupBy('transaction_journal_id')
->whereNull('deleted_at')
@@ -74,12 +60,9 @@ class FixUnevenAmount extends Command
}
}
if (0 === $count) {
$this->info('Amount integrity OK!');
$this->info('Correct: Database amount integrity is OK');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified amount integrity in %s seconds', $end));
return 0;
}

View File

@@ -32,18 +32,8 @@ use Illuminate\Console\Command;
*/
class RemoveBills extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Remove bills from transactions that shouldn\'t have one.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:remove-bills';
protected $signature = 'firefly-iii:remove-bills';
/**
* Execute the console command.
@@ -52,7 +42,6 @@ class RemoveBills extends Command
*/
public function handle(): int
{
$start = microtime(true);
/** @var TransactionType|null $withdrawal */
$withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
if (null === $withdrawal) {
@@ -65,14 +54,10 @@ class RemoveBills extends Command
$journal->bill_id = null;
$journal->save();
}
if (0 === $journals->count()) {
$this->info('All transaction journals have correct bill information.');
}
if ($journals->count() > 0) {
$this->info('Fixed all transaction journals so they have correct bill information.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified bills / journals in %s seconds', $end));
$this->info('Correct: verified bills / journals in %s seconds');
return 0;
}

View File

@@ -31,18 +31,8 @@ use Illuminate\Console\Command;
*/
class RenameMetaFields extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Rename changed meta fields.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:rename-meta-fields';
protected $signature = 'firefly-iii:rename-meta-fields';
private int $count;
@@ -54,7 +44,6 @@ class RenameMetaFields extends Command
public function handle(): int
{
$this->count = 0;
$start = microtime(true);
$changes = [
'original-source' => 'original_source',
@@ -74,15 +63,11 @@ class RenameMetaFields extends Command
$this->rename($original, $update);
}
if (0 === $this->count) {
$this->line('All meta fields are correct.');
$this->info('Correct: all meta fields are correct.');
}
if (0 !== $this->count) {
$this->line(sprintf('Renamed %d meta field(s).', $this->count));
$this->info(sprintf('Renamed %d meta field(s).', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Renamed meta fields in %s seconds', $end));
return 0;
}

View File

@@ -33,18 +33,8 @@ use Illuminate\Support\Facades\Log;
*/
class TransferBudgets extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Removes budgets from transfers.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-transfer-budgets';
protected $signature = 'firefly-iii:fix-transfer-budgets';
/**
* Execute the console command.
@@ -53,7 +43,6 @@ class TransferBudgets extends Command
*/
public function handle(): int
{
$start = microtime(true);
$set = TransactionJournal::distinct()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
@@ -69,8 +58,7 @@ class TransferBudgets extends Command
$count++;
}
if (0 === $count) {
$message = 'No invalid budget/journal entries.';
Log::debug($message);
$message = 'Correct: no invalid budget/journal entries.';
$this->info($message);
}
if (0 !== $count) {
@@ -78,9 +66,6 @@ class TransferBudgets extends Command
Log::debug($message);
$this->line($message);
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified budget/journals in %s seconds.', $end));
return 0;
}
}

View File

@@ -15,18 +15,8 @@ use Illuminate\Support\Facades\Log;
*/
class TriggerCreditCalculation extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Triggers the credit recalculation service for liabilities.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:trigger-credit-recalculation';
protected $signature = 'firefly-iii:trigger-credit-recalculation';
/**
* Execute the console command.
@@ -36,22 +26,13 @@ class TriggerCreditCalculation extends Command
public function handle(): int
{
$this->processAccounts();
return 0;
}
private function processAccounts(): void
{
$accounts = Account::leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
foreach ($accounts as $account) {
Log::debug(sprintf('Processing account #%d ("%s")', $account->id, $account->name));
$this->processAccount($account);
}
return 0;
}
/**
* @param Account $account
*
* @return void
*/
private function processAccount(Account $account): void
@@ -61,4 +42,14 @@ class TriggerCreditCalculation extends Command
$object->setAccount($account);
$object->recalculate();
}
private function processAccounts(): void
{
$accounts = Account::leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
foreach ($accounts as $account) {
$this->processAccount($account);
}
}
}

View File

@@ -38,54 +38,12 @@ use Illuminate\Support\Facades\Log;
class CreateGroupMemberships extends Command
{
public const CONFIG_NAME = '560_create_group_memberships';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update group memberships';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:create-group-memberships';
/**
* Execute the console command.
*
* @return int
* @throws FireflyException
*/
public function handle(): int
{
$start = microtime(true);
$this->createGroupMemberships();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Validated group memberships in %s seconds.', $end));
return 0;
}
/**
*
* @throws FireflyException
*/
private function createGroupMemberships(): void
{
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
Log::debug(sprintf('Manage group memberships for user #%d', $user->id));
self::createGroupMembership($user);
Log::debug(sprintf('Done with user #%d', $user->id));
}
}
protected $signature = 'firefly-iii:create-group-memberships';
/**
* TODO move to helper.
*
* @param User $user
*
* @throws FireflyException
@@ -96,7 +54,6 @@ class CreateGroupMemberships extends Command
$userGroup = UserGroup::where('title', $user->email)->first();
if (null === $userGroup) {
$userGroup = UserGroup::create(['title' => $user->email]);
Log::debug(sprintf('Created new user group #%d ("%s")', $userGroup->id, $userGroup->title));
}
$userRole = UserRole::where('title', UserRole::OWNER)->first();
@@ -115,14 +72,37 @@ class CreateGroupMemberships extends Command
'user_group_id' => $userGroup->id,
]
);
Log::debug('Created new membership.');
}
if (null === $user->user_group_id) {
$user->user_group_id = $userGroup->id;
$user->save();
Log::debug('Put user in default group.');
}
}
Log::debug(sprintf('User #%d now has main group.', $user->id));
/**
* Execute the console command.
*
* @return int
* @throws FireflyException
*/
public function handle(): int
{
$this->createGroupMemberships();
$this->info('Correct: validated group memberships');
return 0;
}
/**
*
* @throws FireflyException
*/
private function createGroupMemberships(): void
{
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
self::createGroupMembership($user);
}
}
}

View File

@@ -55,18 +55,60 @@ class ReportEmptyObjects extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->reportEmptyBudgets();
$this->reportEmptyCategories();
$this->reportEmptyTags();
$this->reportAccounts();
$this->reportBudgetLimits();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Report on empty objects finished in %s seconds', $end));
return 0;
}
/**
* Reports on accounts with no transactions.
*/
private function reportAccounts(): void
{
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
->groupBy(['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email'])
->whereNull('transactions.account_id')
->get(
['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email']
);
/** @var stdClass $entry */
foreach ($set as $entry) {
$line = 'User #%d (%s) has account #%d ("%s") which has no transactions.';
$line = sprintf($line, $entry->user_id, $entry->email, $entry->id, $entry->name);
$this->line($line);
}
}
/**
* Reports on budgets with no budget limits (which makes them pointless).
*/
private function reportBudgetLimits(): void
{
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
->groupBy(['budgets.id', 'budgets.name', 'budgets.encrypted', 'budgets.user_id', 'users.email'])
->whereNull('budget_limits.id')
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'budgets.encrypted', 'users.email']);
/** @var Budget $entry */
foreach ($set as $entry) {
$line = sprintf(
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
$entry->user_id,
$entry->email,
$entry->id,
$entry->name
);
$this->line($line);
}
}
/**
* Report on budgets with no transactions or journals.
*/
@@ -141,49 +183,4 @@ class ReportEmptyObjects extends Command
$this->line($line);
}
}
/**
* Reports on accounts with no transactions.
*/
private function reportAccounts(): void
{
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
->groupBy(['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email'])
->whereNull('transactions.account_id')
->get(
['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email']
);
/** @var stdClass $entry */
foreach ($set as $entry) {
$line = 'User #%d (%s) has account #%d ("%s") which has no transactions.';
$line = sprintf($line, $entry->user_id, $entry->email, $entry->id, $entry->name);
$this->line($line);
}
}
/**
* Reports on budgets with no budget limits (which makes them pointless).
*/
private function reportBudgetLimits(): void
{
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
->groupBy(['budgets.id', 'budgets.name', 'budgets.encrypted', 'budgets.user_id', 'users.email'])
->whereNull('budget_limits.id')
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'budgets.encrypted', 'users.email']);
/** @var Budget $entry */
foreach ($set as $entry) {
$line = sprintf(
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
$entry->user_id,
$entry->email,
$entry->id,
$entry->name
);
$this->line($line);
}
}
}

View File

@@ -61,7 +61,7 @@ class ReportIntegrity extends Command
'firefly-iii:report-empty-objects',
'firefly-iii:report-sum',
'firefly-iii:restore-oauth-keys',
'firefly-iii:upgrade-group-information'
'firefly-iii:upgrade-group-information',
];
foreach ($commands as $command) {
$this->line(sprintf('Now executing %s', $command));

View File

@@ -32,18 +32,8 @@ use Illuminate\Console\Command;
*/
class ReportSum extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Report on the total sum of transactions. Must be 0.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:report-sum';
protected $signature = 'firefly-iii:report-sum';
/**
* Execute the console command.
@@ -62,7 +52,6 @@ class ReportSum extends Command
*/
private function reportSum(): void
{
$start = microtime(true);
/** @var UserRepositoryInterface $userRepository */
$userRepository = app(UserRepositoryInterface::class);
@@ -74,10 +63,8 @@ class ReportSum extends Command
$this->error($message);
}
if (0 === bccomp($sum, '0')) {
$this->info(sprintf('Amount integrity OK for user #%d', $user->id));
$this->info(sprintf('Correct: Amount integrity OK for user #%d', $user->id));
}
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Report on total sum finished in %s seconds', $end));
}
}

View File

@@ -26,25 +26,14 @@ namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Support\System\OAuthKeys;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* Class RestoreOAuthKeys
*/
class RestoreOAuthKeys extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Will restore the OAuth keys generated for the system.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:restore-oauth-keys';
protected $signature = 'firefly-iii:restore-oauth-keys';
/**
* Execute the console command.
@@ -61,40 +50,9 @@ class RestoreOAuthKeys extends Command
/**
*
*/
private function restoreOAuthKeys(): void
private function generateKeys(): void
{
Log::debug('Going to restoreOAuthKeys()');
if (!$this->keysInDatabase() && !$this->keysOnDrive()) {
Log::debug('Keys are not in DB and keys are not on the drive.');
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Generated and stored new keys.');
return;
}
if ($this->keysInDatabase() && !$this->keysOnDrive()) {
Log::debug('Keys are in DB and keys are not on the drive. Restore.');
$result = $this->restoreKeysFromDB();
if (true === $result) {
$this->line('Restored OAuth keys from database.');
return;
}
app('log')->warning('Could not restore keys. Will create new ones.');
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Generated and stored new keys.');
return;
}
if (!$this->keysInDatabase() && $this->keysOnDrive()) {
Log::debug('Keys are not in DB and keys are on the drive. Save in DB.');
$this->storeKeysInDB();
$this->line('Stored OAuth keys in database.');
return;
}
$this->line('OAuth keys are OK');
OAuthKeys::generateKeys();
}
/**
@@ -116,9 +74,43 @@ class RestoreOAuthKeys extends Command
/**
*
*/
private function generateKeys(): void
private function restoreKeysFromDB(): bool
{
OAuthKeys::generateKeys();
return OAuthKeys::restoreKeysFromDB();
}
/**
*
*/
private function restoreOAuthKeys(): void
{
if (!$this->keysInDatabase() && !$this->keysOnDrive()) {
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Correct: generated and stored new keys.');
return;
}
if ($this->keysInDatabase() && !$this->keysOnDrive()) {
$result = $this->restoreKeysFromDB();
if (true === $result) {
$this->line('Correct: restored OAuth keys from database.');
return;
}
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Correct: generated and stored new keys.');
return;
}
if (!$this->keysInDatabase() && $this->keysOnDrive()) {
$this->storeKeysInDB();
$this->line('Correct: stored OAuth keys in database.');
return;
}
$this->line('Correct: OAuth keys are OK');
}
/**
@@ -128,12 +120,4 @@ class RestoreOAuthKeys extends Command
{
OAuthKeys::storeKeysInDB();
}
/**
*
*/
private function restoreKeysFromDB(): bool
{
return OAuthKeys::restoreKeysFromDB();
}
}

View File

@@ -48,18 +48,8 @@ use Illuminate\Database\QueryException;
*/
class UpdateGroupInformation extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Makes sure that every object is linked to a group';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:upgrade-group-information';
protected $signature = 'firefly-iii:upgrade-group-information';
/**
* Execute the console command.
@@ -85,6 +75,7 @@ class UpdateGroupInformation extends Command
$group = $user->userGroup;
if (null === $group) {
$this->warn(sprintf('User "%s" has no group.', $user->email));
return;
}
$set = [
@@ -112,6 +103,7 @@ class UpdateGroupInformation extends Command
* @param User $user
* @param UserGroup $group
* @param string $className
*
* @return void
*/
private function updateGroupInfoForObject(User $user, UserGroup $group, string $className): void
@@ -120,10 +112,11 @@ class UpdateGroupInformation extends Command
$result = $className::where('user_id', $user->id)->where('user_group_id', null)->update(['user_group_id' => $group->id]);
} catch (QueryException $e) {
$this->error(sprintf('Could not update group information for "%s" because of error "%s"', $className, $e->getMessage()));
return;
}
if (0 !== $result) {
$this->line(sprintf('Moved %d %s objects to the correct group.', $result, str_replace('FireflyIII\\Models\\', '', $className)));
$this->info(sprintf('Correct: Moved %d %s objects to the correct group.', $result, str_replace('FireflyIII\\Models\\', '', $className)));
}
}
}

View File

@@ -23,60 +23,55 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\System;
use FireflyIII\Console\Commands\VerifiesAccessToken;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AutoBudget;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* Class ForceDecimalSize
*
* This command was inspired by https://github.com/elliot-gh. It will check all amount fields
* and their values and correct them to the correct number of decimal places. This fixes issues where
* Firefly III would store 0.01 as 0.01000000000000000020816681711721685132943093776702880859375.
*/
class ForceDecimalSize extends Command
{
use VerifiesAccessToken;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:force-decimal-size
{--user=1 : The user ID.}
{--token= : The user\'s access token.}';
protected $description = 'This command resizes DECIMAL columns in MySQL or PostgreSQL and correct amounts (only MySQL).';
protected $signature = 'firefly-iii:force-decimal-size';
private string $cast;
private array $classes
= [
'accounts' => Account::class,
'auto_budgets' => AutoBudget::class,
'available_budgets' => AvailableBudget::class,
'bills' => Bill::class,
'budget_limits' => BudgetLimit::class,
'piggy_bank_events' => PiggyBankEvent::class,
'piggy_bank_repetitions' => PiggyBankRepetition::class,
'piggy_banks' => PiggyBank::class,
'recurrences_transactions' => RecurrenceTransaction::class,
'transactions' => Transaction::class,
];
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command resizes DECIMAL columns in MySQL or PostgreSQL.';
/**
* Execute the console command.
* @throws FireflyException
*/
public function handle(): int
{
if (!$this->verifyAccessToken()) {
$this->error('Invalid access token.');
return 1;
}
$this->error('Running this command is dangerous and can cause data loss.');
$this->error('Please do not continue.');
$question = $this->confirm('Do you want to continue?');
if (true === $question) {
$user = $this->getUser();
Log::channel('audit')->info(sprintf('User #%d ("%s") forced DECIMAL size.', $user->id, $user->email));
$this->updateDecimals();
return 0;
}
$this->line('Done!');
return 0;
}
private function updateDecimals(): void
{
$this->info('Going to force the size of DECIMAL columns. Please hold.');
$tables = [
private string $operator;
private string $regularExpression;
private array $tables
= [
'accounts' => ['virtual_balance'],
'auto_budgets' => ['amount'],
'available_budgets' => ['amount'],
@@ -90,15 +85,484 @@ class ForceDecimalSize extends Command
'recurrences_transactions' => ['amount', 'foreign_amount'],
'transactions' => ['amount', 'foreign_amount'],
];
/**
* Execute the console command.
*
* @throws FireflyException
*/
public function handle(): int
{
Log::debug('Now in ForceDecimalSize::handle()');
$this->determineDatabaseType();
$this->error('Running this command is dangerous and can cause data loss.');
$this->error('Please do not continue.');
$question = $this->confirm('Do you want to continue?');
if (true === $question) {
$this->correctAmounts();
$this->updateDecimals();
}
return 0;
}
/**
* This method loops over all accounts and validates the amounts.
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctAccountAmounts(TransactionCurrency $currency, array $fields): void
{
$operator = $this->operator;
$cast = $this->cast;
$regularExpression = $this->regularExpression;
/** @var Builder $query */
$query = Account::leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string)$currency->id));
$query->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression) {
foreach ($fields as $field) {
$q->orWhere(
DB::raw(sprintf('CAST(accounts.%s AS %s)', $field, $cast)),
$operator,
DB::raw(sprintf($regularExpression, $currency->decimal_places))
);
}
});
$result = $query->get(['accounts.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All accounts in %s', $currency->code));
return;
}
/** @var Account $account */
foreach ($result as $account) {
foreach ($fields as $field) {
$value = $account->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('Account #%d has %s with value "%s", this has been corrected to "%s".', $account->id, $field, $value, $correct));
Account::find($account->id)->update([$field => $correct]);
}
}
}
/**
* This method checks if a basic check can be done or if it needs to be complicated.
*
* @return void
*/
private function correctAmounts(): void
{
// if sqlite, add function?
if ('sqlite' === (string)config('database.default')) {
DB::connection()->getPdo()->sqliteCreateFunction('REGEXP', function ($pattern, $value) {
mb_regex_encoding('UTF-8');
$pattern = trim($pattern, '"');
return (false !== mb_ereg($pattern, (string)$value)) ? 1 : 0;
});
}
if (!in_array((string)config('database.default'), ['mysql', 'pgsql', 'sqlite'], true)) {
$this->line(sprintf('Skip correcting amounts, does not support "%s"...', (string)config('database.default')));
return;
}
$this->correctAmountsByCurrency();
}
/**
* This method loops all enabled currencies and then calls the method that will fix all objects in this currency.
*
* @return void
*/
private function correctAmountsByCurrency(): void
{
$this->line('Going to correct amounts.');
/** @var Collection $enabled */
$enabled = TransactionCurrency::whereEnabled(1)->get();
/** @var TransactionCurrency $currency */
foreach ($enabled as $currency) {
$this->correctByCurrency($currency);
}
}
/**
* This method loops the available tables that may need fixing, and calls for the right method that can fix them.
*
* @param TransactionCurrency $currency
*
* @return void
* @throws FireflyException
*/
private function correctByCurrency(TransactionCurrency $currency): void
{
$this->line(sprintf('Going to correct amounts in currency %s ("%s").', $currency->code, $currency->name));
/**
* @var string $name
* @var array $fields
*/
foreach($tables as $name => $fields) {
foreach ($this->tables as $name => $fields) {
switch ($name) {
default:
$message = sprintf('Cannot handle table "%s"', $name);
$this->line($message);
throw new FireflyException($message);
case 'accounts':
$this->correctAccountAmounts($currency, $fields);
break;
case 'auto_budgets':
case 'available_budgets':
case 'bills':
case 'budget_limits':
case 'recurrences_transactions':
$this->correctGeneric($currency, $name);
break;
case 'currency_exchange_rates':
case 'limit_repetitions':
// do nothing
break;
case 'piggy_bank_events':
$this->correctPiggyEventAmounts($currency, $fields);
break;
case 'piggy_bank_repetitions':
$this->correctPiggyRepetitionAmounts($currency, $fields);
break;
case 'piggy_banks':
$this->correctPiggyAmounts($currency, $fields);
break;
case 'transactions':
$this->correctTransactionAmounts($currency);
break;
}
}
}
/**
* This method fixes all auto budgets in currency $currency.
*
* @param TransactionCurrency $currency
* @param string $table
*
* @return void
*/
private function correctGeneric(TransactionCurrency $currency, string $table): void
{
$class = $this->classes[$table];
$fields = $this->tables[$table];
$operator = $this->operator;
$cast = $this->cast;
$regularExpression = $this->regularExpression;
/** @var Builder $query */
$query = $class::where('transaction_currency_id', $currency->id)->where(
static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression) {
foreach ($fields as $field) {
$q->orWhere(
DB::raw(sprintf('CAST(%s AS %s)', $field, $cast)),
$operator,
DB::raw(sprintf($regularExpression, $currency->decimal_places))
);
}
}
);
$result = $query->get(['*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All %s in %s', $table, $currency->code));
return;
}
/** @var Model $item */
foreach ($result as $item) {
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('%s #%d has %s with value "%s", this has been corrected to "%s".', $table, $item->id, $field, $value, $correct));
$class::find($item->id)->update([$field => $correct]);
}
}
}
/**
* This method fixes all piggy banks in currency $currency.
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctPiggyAmounts(TransactionCurrency $currency, array $fields): void
{
$operator = $this->operator;
$cast = $this->cast;
$regularExpression = $this->regularExpression;
/** @var Builder $query */
$query = PiggyBank::leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string)$currency->id))
->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression) {
foreach ($fields as $field) {
$q->orWhere(
DB::raw(sprintf('CAST(piggy_banks.%s AS %s)', $field, $cast)),
$operator,
DB::raw(sprintf($regularExpression, $currency->decimal_places))
);
}
});
$result = $query->get(['piggy_banks.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All piggy banks in %s', $currency->code));
return;
}
/** @var PiggyBank $item */
foreach ($result as $item) {
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('Piggy bank #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct));
PiggyBank::find($item->id)->update([$field => $correct]);
}
}
}
/**
* This method fixes all piggy bank events in currency $currency.
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctPiggyEventAmounts(TransactionCurrency $currency, array $fields): void
{
$operator = $this->operator;
$cast = $this->cast;
$regularExpression = $this->regularExpression;
/** @var Builder $query */
$query = PiggyBankEvent::leftJoin('piggy_banks', 'piggy_bank_events.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string)$currency->id))
->where(static function (Builder $q) use ($fields, $currency, $cast, $operator, $regularExpression) {
foreach ($fields as $field) {
$q->orWhere(
DB::raw(sprintf('CAST(piggy_bank_events.%s AS %s)', $field, $cast)),
$operator,
DB::raw(sprintf($regularExpression, $currency->decimal_places))
);
}
});
$result = $query->get(['piggy_bank_events.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All piggy bank events in %s', $currency->code));
return;
}
/** @var PiggyBankEvent $item */
foreach ($result as $item) {
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('Piggy bank event #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct));
PiggyBankEvent::find($item->id)->update([$field => $correct]);
}
}
}
/**
* This method fixes all piggy bank repetitions in currency $currency.
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctPiggyRepetitionAmounts(TransactionCurrency $currency, array $fields)
{
$operator = $this->operator;
$cast = $this->cast;
$regularExpression = $this->regularExpression;
// select all piggy bank repetitions with this currency and issue.
/** @var Builder $query */
$query = PiggyBankRepetition::leftJoin('piggy_banks', 'piggy_bank_repetitions.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string)$currency->id))
->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression) {
foreach ($fields as $field) {
$q->orWhere(
DB::raw(sprintf('CAST(piggy_bank_repetitions.%s AS %s)', $field, $cast)),
$operator,
DB::raw(sprintf($regularExpression, $currency->decimal_places))
);
}
});
$result = $query->get(['piggy_bank_repetitions.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All piggy bank repetitions in %s', $currency->code));
return;
}
/** @var PiggyBankRepetition $item */
foreach ($result as $item) {
foreach ($fields as $field) {
$value = $item->$field;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('Piggy bank repetition #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct));
PiggyBankRepetition::find($item->id)->update([$field => $correct]);
}
}
}
/**
* This method fixes all transactions in currency $currency.
*
* @param TransactionCurrency $currency
*
* @return void
*/
private function correctTransactionAmounts(TransactionCurrency $currency): void
{
// select all transactions with this currency and issue.
/** @var Builder $query */
$query = Transaction::where('transaction_currency_id', $currency->id)->where(
DB::raw(sprintf('CAST(amount as %s)', $this->cast)),
$this->operator,
DB::raw(sprintf($this->regularExpression, $currency->decimal_places))
);
$result = $query->get(['transactions.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All transactions in %s', $currency->code));
}
/** @var Transaction $item */
foreach ($result as $item) {
$value = $item->amount;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('Transaction #%d has amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct));
Transaction::find($item->id)->update(['amount' => $correct]);
}
// select all transactions with this FOREIGN currency and issue.
/** @var Builder $query */
$query = Transaction::where('foreign_currency_id', $currency->id)->where(
DB::raw(sprintf('CAST(foreign_amount as %s)', $this->cast)),
$this->operator,
DB::raw(sprintf($this->regularExpression, $currency->decimal_places))
);
$result = $query->get(['*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All transactions in foreign currency %s', $currency->code));
return;
}
/** @var Transaction $item */
foreach ($result as $item) {
$value = $item->foreign_amount;
if (null === $value) {
continue;
}
// fix $field by rounding it down correctly.
$pow = pow(10, (int)$currency->decimal_places);
$correct = bcdiv((string)round($value * $pow), (string)$pow, 12);
$this->line(sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct));
Transaction::find($item->id)->update(['foreign_amount' => $correct]);
}
}
private function determineDatabaseType(): void
{
// switch stuff based on database connection:
$this->operator = 'REGEXP';
$this->regularExpression = '\'\\\\.[\\\\d]{%d}[1-9]+\'';
$this->cast = 'CHAR';
if ('pgsql' === config('database.default')) {
$this->operator = 'SIMILAR TO';
$this->regularExpression = '\'%%\.[\d]{%d}[1-9]+%%\'';
$this->cast = 'TEXT';
}
if ('sqlite' === config('database.default')) {
$this->regularExpression = '"\\.[\d]{%d}[1-9]+"';
}
}
/**
* @return void
*/
private function updateDecimals(): void
{
$this->info('Going to force the size of DECIMAL columns. Please hold.');
$type = (string)config('database.default');
/**
* @var string $name
* @var array $fields
*/
foreach ($this->tables as $name => $fields) {
/** @var string $field */
foreach($fields as $field) {
foreach ($fields as $field) {
$this->line(sprintf('Updating table "%s", field "%s"...', $name, $field));
$query = sprintf('ALTER TABLE %s CHANGE COLUMN %s %s DECIMAL(32, 12);', $name, $field, $field);
switch ($type) {
default:
$this->error(sprintf('Cannot handle database type "%s".', $type));
return;
case 'pgsql':
$query = sprintf('ALTER TABLE %s ALTER COLUMN %s TYPE DECIMAL(32,12);', $name, $field);
break;
case 'mysql':
$query = sprintf('ALTER TABLE %s CHANGE COLUMN %s %s DECIMAL(32, 12);', $name, $field, $field);
break;
}
DB::select($query);
sleep(1);
}

View File

@@ -35,6 +35,12 @@ class ForceMigration extends Command
{
use VerifiesAccessToken;
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will force-run all database migrations.';
/**
* The name and signature of the console command.
*
@@ -44,15 +50,9 @@ class ForceMigration extends Command
{--user=1 : The user ID.}
{--token= : The user\'s access token.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will force-run all database migrations.';
/**
* Execute the console command.
*
* @throws FireflyException
*/
public function handle(): int
@@ -70,8 +70,10 @@ class ForceMigration extends Command
$user = $this->getUser();
Log::channel('audit')->info(sprintf('User #%d ("%s") forced migrations.', $user->id, $user->email));
$this->forceMigration();
return 0;
}
return 0;
}
@@ -81,12 +83,10 @@ class ForceMigration extends Command
$this->line('Dropping "migrations" table...');
sleep(2);
Schema::dropIfExists('migrations');
$this->line('Done!');
$this->line('Re-run all migrations...');
Artisan::call('migrate', ['--seed' => true]);
sleep(2);
$this->line('');
$this->info('Done!');
$this->line('There is a good chance you just saw a lot of error messages.');
$this->line('No need to panic yet. First try to access Firefly III (again).');
$this->line('The issue, whatever it was, may have been solved now.');

View File

@@ -66,52 +66,6 @@ class UpgradeFireflyInstructions extends Command
return 0;
}
/**
* Render upgrade instructions.
*/
private function updateInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text.upgrade');
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
if (\str_starts_with($version, $compare)) {
$text = $config[$compare];
}
}
$this->showLine();
$this->boxed('');
if (null === $text || '' === $text) {
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version));
$this->boxedInfo('There are no extra upgrade instructions.');
$this->boxed('Firefly III should be ready for use.');
$this->boxed('');
$this->showLine();
return;
}
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s!', $version));
$this->boxedInfo($text);
$this->boxed('');
$this->showLine();
}
/**
* Show a line.
*/
private function showLine(): void
{
$line = '+';
$line .= str_repeat('-', 78);
$line .= '+';
$this->line($line);
}
/**
* Show a nice box.
*
@@ -153,6 +107,9 @@ class UpgradeFireflyInstructions extends Command
$text = $config[$compare];
}
}
$this->newLine();
$this->showLogo();
$this->newLine();
$this->showLine();
$this->boxed('');
if (null === $text || '' === $text) {
@@ -170,4 +127,90 @@ class UpgradeFireflyInstructions extends Command
$this->boxed('');
$this->showLine();
}
/**
* Show a line.
*/
private function showLine(): void
{
$line = '+';
$line .= str_repeat('-', 78);
$line .= '+';
$this->line($line);
}
/**
* The logo takes up 8 lines of code. So 8 colors can be used.
* @return void
*/
private function showLogo(): void
{
$today = date('m-d');
$month = date('m');
// variation in colors and effects just because I can!
// default is Ukraine flag:
$colors = ['blue', 'blue', 'blue', 'yellow', 'yellow', 'yellow', 'default', 'default'];
// 5th of May is Dutch liberation day and 29th of April is Dutch King's Day and September 17 is my birthday.
if ('05-01' === $today || '04-29' === $today || '09-17' === $today) {
$colors = ['red', 'red', 'red', 'white', 'white', 'blue', 'blue', 'blue'];
}
// National Coming Out Day, International Day Against Homophobia, Biphobia and Transphobia and Pride Month
if ('10-11' === $today || '05-17' === $today || '06' === $month) {
$colors = ['red', 'bright-red', 'yellow', 'green', 'blue', 'magenta', 'default', 'default'];
}
// International Transgender Day of Visibility
if ('03-31' === $today) {
$colors = ['bright-blue', 'bright-red', 'white', 'white', 'bright-red', 'bright-blue', 'default', 'default'];
}
$this->line(sprintf('<fg=%s> ______ _ __ _ _____ _____ _____ </>', $colors[0]));
$this->line(sprintf('<fg=%s> | ____(_) / _| | |_ _|_ _|_ _| </>', $colors[1]));
$this->line(sprintf('<fg=%s> | |__ _ _ __ ___| |_| |_ _ | | | | | | </>', $colors[2]));
$this->line(sprintf('<fg=%s> | __| | | \'__/ _ \ _| | | | | | | | | | | </>', $colors[3]));
$this->line(sprintf('<fg=%s> | | | | | | __/ | | | |_| | _| |_ _| |_ _| |_ </>', $colors[4]));
$this->line(sprintf('<fg=%s> |_| |_|_| \___|_| |_|\__, | |_____|_____|_____| </>', $colors[5]));
$this->line(sprintf('<fg=%s> __/ | </>', $colors[6]));
$this->line(sprintf('<fg=%s> |___/ </>', $colors[7]));
}
/**
* Render upgrade instructions.
*/
private function updateInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text.upgrade');
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
if (\str_starts_with($version, $compare)) {
$text = $config[$compare];
}
}
$this->newLine();
$this->showLogo();
$this->newLine();
$this->showLine();
$this->boxed('');
if (null === $text || '' === $text) {
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version));
$this->boxedInfo('There are no extra upgrade instructions.');
$this->boxed('Firefly III should be ready for use.');
$this->boxed('');
$this->showLine();
return;
}
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s!', $version));
$this->boxedInfo($text);
$this->boxed('');
$this->showLine();
}
}

View File

@@ -124,6 +124,7 @@ class VerifySecurityAlerts extends Command
/**
* @param array $array
*
* @return void
*/
private function saveSecurityAdvisory(array $array): void

View File

@@ -31,8 +31,8 @@ use FireflyIII\Support\Cronjobs\BillWarningCronjob;
use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Illuminate\Support\Facades\Log;
use InvalidArgumentException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -123,6 +123,63 @@ class Cron extends Command
return 0;
}
/**
* @param bool $force
* @param Carbon|null $date
*
*/
private function autoBudgetCronJob(bool $force, ?Carbon $date): void
{
$autoBudget = new AutoBudgetCronjob();
$autoBudget->setForce($force);
// set date in cron job:
if (null !== $date) {
$autoBudget->setDate($date);
}
$autoBudget->fire();
if ($autoBudget->jobErrored) {
$this->error(sprintf('Error in "create auto budgets" cron: %s', $autoBudget->message));
}
if ($autoBudget->jobFired) {
$this->line(sprintf('"Create auto budgets" cron fired: %s', $autoBudget->message));
}
if ($autoBudget->jobSucceeded) {
$this->info(sprintf('"Create auto budgets" cron ran with success: %s', $autoBudget->message));
}
}
/**
* @param bool $force
* @param Carbon|null $date
*
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function billWarningCronJob(bool $force, ?Carbon $date): void
{
$autoBudget = new BillWarningCronjob();
$autoBudget->setForce($force);
// set date in cron job:
if (null !== $date) {
$autoBudget->setDate($date);
}
$autoBudget->fire();
if ($autoBudget->jobErrored) {
$this->error(sprintf('Error in "bill warnings" cron: %s', $autoBudget->message));
}
if ($autoBudget->jobFired) {
$this->line(sprintf('"Send bill warnings" cron fired: %s', $autoBudget->message));
}
if ($autoBudget->jobSucceeded) {
$this->info(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
}
}
/**
* @param bool $force
* @param Carbon|null $date
@@ -178,60 +235,4 @@ class Cron extends Command
$this->info(sprintf('"Create recurring transactions" cron ran with success: %s', $recurring->message));
}
}
/**
* @param bool $force
* @param Carbon|null $date
*
*/
private function autoBudgetCronJob(bool $force, ?Carbon $date): void
{
$autoBudget = new AutoBudgetCronjob();
$autoBudget->setForce($force);
// set date in cron job:
if (null !== $date) {
$autoBudget->setDate($date);
}
$autoBudget->fire();
if ($autoBudget->jobErrored) {
$this->error(sprintf('Error in "create auto budgets" cron: %s', $autoBudget->message));
}
if ($autoBudget->jobFired) {
$this->line(sprintf('"Create auto budgets" cron fired: %s', $autoBudget->message));
}
if ($autoBudget->jobSucceeded) {
$this->info(sprintf('"Create auto budgets" cron ran with success: %s', $autoBudget->message));
}
}
/**
* @param bool $force
* @param Carbon|null $date
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function billWarningCronJob(bool $force, ?Carbon $date): void
{
$autoBudget = new BillWarningCronjob();
$autoBudget->setForce($force);
// set date in cron job:
if (null !== $date) {
$autoBudget->setDate($date);
}
$autoBudget->fire();
if ($autoBudget->jobErrored) {
$this->error(sprintf('Error in "bill warnings" cron: %s', $autoBudget->message));
}
if ($autoBudget->jobFired) {
$this->line(sprintf('"Send bill warnings" cron fired: %s', $autoBudget->message));
}
if ($autoBudget->jobSucceeded) {
$this->info(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
}
}
}

View File

@@ -43,65 +43,62 @@ use Psr\Container\NotFoundExceptionInterface;
class AccountCurrencies extends Command
{
public const CONFIG_NAME = '480_account_currencies';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Give all accounts proper currency info.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}';
/** @var AccountRepositoryInterface */
private $accountRepos;
/** @var int */
private $count;
/** @var UserRepositoryInterface */
private $userRepos;
protected $signature = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}';
private AccountRepositoryInterface $accountRepos;
private int $count;
private UserRepositoryInterface $userRepos;
/**
* Each (asset) account must have a reference to a preferred currency. If the account does not have one, it's forced upon the account.
*
* @return int
* @throws ContainerExceptionInterface
* @throws FireflyException
* @throws NotFoundExceptionInterface
*/
public function handle(): int
{
Log::debug('Now in handle()');
$this->stupidLaravel();
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->info('Correct: this command has already been executed.');
return 0;
}
$this->updateAccountCurrencies();
if (0 === $this->count) {
$this->line('All accounts are OK.');
$this->info('Correct: all account currencies are OK.');
}
if (0 !== $this->count) {
$this->line(sprintf('Corrected %d account(s).', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed account currencies in %s seconds.', $end));
$this->markAsExecuted();
return 0;
}
/**
* @return bool
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
return (bool)$configVar?->data;
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
@@ -111,18 +108,48 @@ class AccountCurrencies extends Command
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @param Account $account
* @param TransactionCurrency $currency
*/
private function isExecuted(): bool
private function updateAccount(Account $account, TransactionCurrency $currency): void
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
$this->accountRepos->setUser($account->user);
$accountCurrency = (int)$this->accountRepos->getMetaValue($account, 'currency_id');
$openingBalance = $this->accountRepos->getOpeningBalance($account);
$obCurrency = (int)$openingBalance?->transaction_currency_id;
// both 0? set to default currency:
if (0 === $accountCurrency && 0 === $obCurrency) {
AccountMeta::where('account_id', $account->id)->where('name', 'currency_id')->forceDelete();
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $currency->code));
$this->count++;
return;
}
return false;
// account is set to 0, opening balance is not?
if (0 === $accountCurrency && $obCurrency > 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (#%d).', $account->id, $account->name, $obCurrency));
$this->count++;
return;
}
// do not match and opening balance id is not null.
if ($accountCurrency !== $obCurrency && null !== $openingBalance) {
// update opening balance:
$openingBalance->transaction_currency_id = $accountCurrency;
$openingBalance->save();
$openingBalance->transactions->each(
static function (Transaction $transaction) use ($accountCurrency) {
$transaction->transaction_currency_id = $accountCurrency;
$transaction->save();
}
);
$this->line(sprintf('Account #%d ("%s") now has a correct currency for opening balance.', $account->id, $account->name));
$this->count++;
}
}
/**
@@ -130,10 +157,8 @@ class AccountCurrencies extends Command
*/
private function updateAccountCurrencies(): void
{
Log::debug('Now in updateAccountCurrencies()');
$users = $this->userRepos->all();
$defaultCurrencyCode = (string)config('firefly.default_currency', 'EUR');
Log::debug(sprintf('Default currency is %s', $defaultCurrencyCode));
foreach ($users as $user) {
$this->updateCurrenciesForUser($user, $defaultCurrencyCode);
}
@@ -147,7 +172,6 @@ class AccountCurrencies extends Command
*/
private function updateCurrenciesForUser(User $user, string $systemCurrencyCode): void
{
Log::debug(sprintf('Now in updateCurrenciesForUser(%s, %s)', $user->email, $systemCurrencyCode));
$this->accountRepos->setUser($user);
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
@@ -156,7 +180,6 @@ class AccountCurrencies extends Command
if (!is_string($defaultCurrencyCode)) {
$defaultCurrencyCode = $systemCurrencyCode;
}
Log::debug(sprintf('Users currency pref is %s', $defaultCurrencyCode));
/** @var TransactionCurrency|null $defaultCurrency */
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
@@ -173,72 +196,4 @@ class AccountCurrencies extends Command
$this->updateAccount($account, $defaultCurrency);
}
}
/**
* @param Account $account
* @param TransactionCurrency $currency
*/
private function updateAccount(Account $account, TransactionCurrency $currency): void
{
Log::debug(sprintf('Now in updateAccount(%d, %s)', $account->id, $currency->code));
$this->accountRepos->setUser($account->user);
$accountCurrency = (int)$this->accountRepos->getMetaValue($account, 'currency_id');
Log::debug(sprintf('Account currency is #%d', $accountCurrency));
$openingBalance = $this->accountRepos->getOpeningBalance($account);
$obCurrency = 0;
if (null !== $openingBalance) {
$obCurrency = (int)$openingBalance->transaction_currency_id;
Log::debug('Account has opening balance.');
}
Log::debug(sprintf('Account OB currency is #%d.', $obCurrency));
// both 0? set to default currency:
if (0 === $accountCurrency && 0 === $obCurrency) {
Log::debug(sprintf('Both currencies are 0, so reset to #%d (%s)', $currency->id, $currency->code));
AccountMeta::where('account_id', $account->id)->where('name', 'currency_id')->forceDelete();
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $currency->code));
$this->count++;
return;
}
// account is set to 0, opening balance is not?
if (0 === $accountCurrency && $obCurrency > 0) {
Log::debug(sprintf('Account is #0, OB is #%d, so set account to OB as well', $obCurrency));
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (#%d).', $account->id, $account->name, $obCurrency));
$this->count++;
return;
}
// do not match and opening balance id is not null.
if ($accountCurrency !== $obCurrency && null !== $openingBalance) {
Log::debug(sprintf('Account (#%d) and OB currency (#%d) are different. Overrule OB, set to account currency.', $accountCurrency, $obCurrency));
// update opening balance:
$openingBalance->transaction_currency_id = $accountCurrency;
$openingBalance->save();
$openingBalance->transactions->each(
static function (Transaction $transaction) use ($accountCurrency) {
$transaction->transaction_currency_id = $accountCurrency;
$transaction->save();
}
);
$this->line(sprintf('Account #%d ("%s") now has a correct currency for opening balance.', $account->id, $account->name));
$this->count++;
return;
}
Log::debug('No changes necessary for this account.');
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -56,47 +56,18 @@ class AppendBudgetLimitPeriods extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->info('Correct: this command has already been executed.');
return 0;
}
$this->theresNoLimit();
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Fixed budget limits in %s seconds.', $end));
return 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
return (bool)$configVar->data;
}
/**
*
*/
private function theresNoLimit(): void
{
$limits = BudgetLimit::whereNull('period')->get();
/** @var BudgetLimit $limit */
foreach ($limits as $limit) {
$this->fixLimit($limit);
}
}
/**
* @param BudgetLimit $limit
*/
@@ -182,6 +153,18 @@ class AppendBudgetLimitPeriods extends Command
return null;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
return (bool)$configVar->data;
}
/**
*
*/
@@ -189,4 +172,16 @@ class AppendBudgetLimitPeriods extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
*
*/
private function theresNoLimit(): void
{
$limits = BudgetLimit::whereNull('period')->get();
/** @var BudgetLimit $limit */
foreach ($limits as $limit) {
$this->fixLimit($limit);
}
}
}

View File

@@ -64,12 +64,11 @@ class BackToJournals extends Command
*/
public function handle(): int
{
$start = microtime(true);
if (!$this->isMigrated()) {
$this->error('Please run firefly-iii:migrate-to-groups first.');
}
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->info('Correct: this command has already been executed.');
return 0;
}
@@ -79,23 +78,46 @@ class BackToJournals extends Command
$this->migrateAll();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Updated category and budget info for all transaction journals in %s seconds.', $end));
$this->info('Correct: updated category and budget info for all transaction journals');
$this->markAsExecuted();
return 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @return array
*/
private function isMigrated(): bool
private function getIdsForBudgets(): array
{
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
$transactions = DB::table('budget_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
return (bool)$configVar->data;
foreach ($chunks as $chunk) {
$set = DB::table('transactions')->whereIn('transactions.id', $chunk)->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
* @return array
*/
private function getIdsForCategories(): array
{
$transactions = DB::table('category_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')
->whereIn('transactions.id', $chunk)
->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
@@ -110,12 +132,31 @@ class BackToJournals extends Command
return (bool)$configVar->data;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isMigrated(): bool
{
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
return (bool)$configVar->data;
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
*
*/
private function migrateAll(): void
{
Log::debug('Now in migrateAll()');
$this->migrateBudgets();
$this->migrateCategories();
@@ -143,23 +184,6 @@ class BackToJournals extends Command
}
}
/**
* @return array
*/
private function getIdsForBudgets(): array
{
$transactions = DB::table('budget_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')->whereIn('transactions.id', $chunk)->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
* @param TransactionJournal $journal
*/
@@ -198,44 +222,21 @@ class BackToJournals extends Command
*/
private function migrateCategories(): void
{
Log::debug('Now in migrateCategories()');
$journals = new Collection();
$allIds = $this->getIdsForCategories();
Log::debug(sprintf('Total: %d', count($allIds)));
$chunks = array_chunk($allIds, 500);
foreach ($chunks as $chunk) {
Log::debug('Now doing a chunk.');
$collected = TransactionJournal::whereIn('id', $chunk)->with(['transactions', 'categories', 'transactions.categories'])->get();
$journals = $journals->merge($collected);
}
$this->line(sprintf('Check %d transaction journal(s) for category info.', count($journals)));
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$this->migrateCategoriesForJournal($journal);
}
}
/**
* @return array
*/
private function getIdsForCategories(): array
{
$transactions = DB::table('category_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')
->whereIn('transactions.id', $chunk)
->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
* @param TransactionJournal $journal
*/
@@ -265,12 +266,4 @@ class BackToJournals extends Command
$journal->categories()->sync([(int)$category->id]);
}
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -58,10 +58,8 @@ class BudgetLimitCurrency extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->info('Correct: this command has already been executed.');
return 0;
}
@@ -88,11 +86,8 @@ class BudgetLimitCurrency extends Command
}
}
if (0 === $count) {
$this->info('All budget limits are correct.');
$this->info('Correct: all budget limits are OK.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified budget limits in %s seconds.', $end));
$this->markAsExecuted();
return 0;

View File

@@ -37,18 +37,8 @@ use Psr\Container\NotFoundExceptionInterface;
class CCLiabilities extends Command
{
public const CONFIG_NAME = '480_cc_liabilities';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Convert old credit card liabilities.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:cc-liabilities {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:cc-liabilities {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
@@ -62,9 +52,8 @@ class CCLiabilities extends Command
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->info('Correct: this command has already been executed.');
return 0;
}
@@ -73,7 +62,8 @@ class CCLiabilities extends Command
$ccType = AccountType::where('type', AccountType::CREDITCARD)->first();
$debtType = AccountType::where('type', AccountType::DEBT)->first();
if (null === $ccType || null === $debtType) {
$this->info('No incorrectly stored credit card liabilities.');
$this->info('Correct: no incorrectly stored credit card liabilities.');
$this->markAsExecuted();
return 0;
}
@@ -88,7 +78,7 @@ class CCLiabilities extends Command
$this->info('Credit card liability types are no longer supported and have been converted to generic debts. See: https://bit.ly/FF3-credit-cards');
}
if (0 === $accounts->count()) {
$this->info('No incorrectly stored credit card liabilities.');
$this->info('Correct: no incorrectly stored credit card liabilities.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified credit card liabilities in %s seconds', $end));

View File

@@ -41,18 +41,8 @@ use stdClass;
*/
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-iii:decrypt-all';
protected $signature = 'firefly-iii:decrypt-all';
/**
* Execute the console command.
@@ -61,7 +51,6 @@ class DecryptDatabase extends Command
*/
public function handle(): int
{
$this->line('Going to decrypt the database.');
$tables = [
'accounts' => ['name', 'iban'],
'attachments' => ['filename', 'mime', 'title', 'description'],
@@ -82,56 +71,9 @@ class DecryptDatabase extends Command
foreach ($tables as $table => $fields) {
$this->decryptTable($table, $fields);
}
$this->info('Done!');
return 0;
}
/**
* @param string $table
* @param array $fields
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function decryptTable(string $table, array $fields): void
{
if ($this->isDecrypted($table)) {
$this->info(sprintf('No decryption required for table "%s".', $table));
return;
}
foreach ($fields as $field) {
$this->decryptField($table, $field);
}
$this->line(sprintf('Decrypted the data in table "%s".', $table));
// mark as decrypted:
$configName = sprintf('is_decrypted_%s', $table);
app('fireflyconfig')->set($configName, true);
}
/**
* @param string $table
*
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isDecrypted(string $table): bool
{
$configName = sprintf('is_decrypted_%s', $table);
$configVar = null;
try {
$configVar = app('fireflyconfig')->get($configName, false);
} catch (FireflyException $e) {
Log::error($e->getMessage());
}
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
* @param string $table
* @param string $field
@@ -145,6 +87,33 @@ class DecryptDatabase extends Command
}
}
/**
* @param int $id
* @param string $value
*/
private function decryptPreferencesRow(int $id, string $value): void
{
// try to json_decrypt the value.
try {
$newValue = json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value;
} catch (JsonException $e) {
$message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage());
$this->error($message);
app('log')->warning($message);
app('log')->warning($value);
app('log')->warning($e->getTraceAsString());
return;
}
/** @var Preference $object */
$object = Preference::find((int)$id);
if (null !== $object) {
$object->data = $newValue;
$object->save();
}
}
/**
* @param string $table
* @param string $field
@@ -180,6 +149,52 @@ class DecryptDatabase extends Command
}
}
/**
* @param string $table
* @param array $fields
*
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function decryptTable(string $table, array $fields): void
{
if ($this->isDecrypted($table)) {
$this->info(sprintf('Correct: no decryption required for table "%s".', $table));
return;
}
foreach ($fields as $field) {
$this->decryptField($table, $field);
}
$this->line(sprintf('Correct: decrypted the data in table "%s".', $table));
// mark as decrypted:
$configName = sprintf('is_decrypted_%s', $table);
app('fireflyconfig')->set($configName, true);
}
/**
* @param string $table
*
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isDecrypted(string $table): bool
{
$configName = sprintf('is_decrypted_%s', $table);
$configVar = null;
try {
$configVar = app('fireflyconfig')->get($configName, false);
} catch (FireflyException $e) {
Log::error($e->getMessage());
}
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
* Tries to decrypt data. Will only throw an exception when the MAC is invalid.
*
@@ -200,31 +215,4 @@ class DecryptDatabase extends Command
return $value;
}
/**
* @param int $id
* @param string $value
*/
private function decryptPreferencesRow(int $id, string $value): void
{
// try to json_decrypt the value.
try {
$newValue = json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value;
} catch (JsonException $e) {
$message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage());
$this->error($message);
app('log')->warning($message);
app('log')->warning($value);
app('log')->warning($e->getTraceAsString());
return;
}
/** @var Preference $object */
$object = Preference::find((int)$id);
if (null !== $object) {
$object->data = $newValue;
$object->save();
}
}
}

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