Compare commits

...

257 Commits

Author SHA1 Message Date
James Cole
7d438375c1 Merge branch 'release/5.7.1' 2022-04-04 05:48:39 +02:00
James Cole
b4638e1ae5 Rebuild meta files for new release. 2022-04-04 05:48:15 +02:00
James Cole
9872c18715 Update meta-files for new release. 2022-04-04 05:46:16 +02:00
James Cole
e854c1b8ae Fix #5961 2022-04-04 05:40:29 +02:00
James Cole
b8f2f0a73f Catch null 2022-04-03 17:47:27 +02:00
James Cole
8c481e38f2 Update supported releases. 2022-04-03 16:24:19 +02:00
James Cole
609e911fd6 Make sure the wort things aren't broken. 2022-04-03 16:23:49 +02:00
James Cole
d894ccc9cc Catch missing date ranges. 2022-04-03 14:48:22 +02:00
James Cole
19d4b6ba86 Fix null pointer 2022-04-03 14:43:06 +02:00
James Cole
789dba7cf9 Fix https://github.com/firefly-iii/firefly-iii/issues/5958 2022-04-03 14:42:12 +02:00
James Cole
b6e88a56c5 Fix null pointer. 2022-04-03 14:40:42 +02:00
James Cole
b96a9a359c Remove token header 2022-04-03 12:39:30 +02:00
James Cole
ba64a7d039 Add error method 2022-04-03 12:38:17 +02:00
James Cole
20c8fea520 Merge tag '5.7.0' into develop
5.7.0
2022-04-03 12:13:37 +02:00
James Cole
e6854b9265 Merge branch 'release/5.7.0' 2022-04-03 12:13:35 +02:00
James Cole
122cab1757 Update meta files for new release. 2022-04-03 12:12:41 +02:00
James Cole
51b07f08ac Remove extra character. 2022-04-02 09:25:28 +02:00
James Cole
e453ee19a1 Update packages 2022-04-02 09:25:21 +02:00
James Cole
4786c97c0b Remove extra line. 2022-04-02 09:25:14 +02:00
James Cole
b5d4e82f45 Fix https://github.com/firefly-iii/firefly-iii/issues/5949 2022-04-01 07:37:45 +02:00
James Cole
c0072625c6 Merge branch 'main' into develop 2022-03-31 06:22:16 +02:00
James Cole
8c2455e8dd Update its_you_not_me.md 2022-03-31 04:21:50 +00:00
James Cole
55c82b2a0f Update support.md 2022-03-31 04:16:47 +00:00
James Cole
3120e29940 Update packages. 2022-03-30 20:09:19 +02:00
James Cole
1211a5c878 Remove log entry. 2022-03-30 06:58:41 +02:00
James Cole
8f98be32f9 Fix various sonatype issues. 2022-03-30 06:54:59 +02:00
James Cole
65764199fe Merge branch 'main' into develop 2022-03-30 06:35:35 +02:00
James Cole
9ce39f5724 Merge pull request #5946 from firefly-iii/dependabot/composer/guzzlehttp/psr7-2.2.1
Bump guzzlehttp/psr7 from 2.1.0 to 2.2.1
2022-03-30 06:34:49 +02:00
James Cole
59922e6c2e Expanding the account overview but still a bit stuck on the delete option. 2022-03-30 06:34:37 +02:00
dependabot[bot]
cb62469a80 Bump guzzlehttp/psr7 from 2.1.0 to 2.2.1
Bumps [guzzlehttp/psr7](https://github.com/guzzle/psr7) from 2.1.0 to 2.2.1.
- [Release notes](https://github.com/guzzle/psr7/releases)
- [Changelog](https://github.com/guzzle/psr7/blob/master/CHANGELOG.md)
- [Commits](https://github.com/guzzle/psr7/compare/2.1.0...2.2.1)

---
updated-dependencies:
- dependency-name: guzzlehttp/psr7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-29 22:18:38 +00:00
James Cole
3df8c4ff75 Replace deprecated method 2022-03-29 17:01:05 +02:00
James Cole
cf4c1d8089 Update translations. 2022-03-29 16:42:26 +02:00
James Cole
88539497bf Rename variable. 2022-03-29 16:42:10 +02:00
James Cole
123693096c Reformat various code. 2022-03-29 15:10:05 +02:00
James Cole
60786461a9 Reformat various code. 2022-03-29 15:01:48 +02:00
James Cole
452b6d0e1b Reformat various code. 2022-03-29 15:01:12 +02:00
James Cole
d04efb8325 Reformat various code. 2022-03-29 15:00:29 +02:00
James Cole
d1a09ff33b Reformat various code. 2022-03-29 14:59:58 +02:00
James Cole
29bed2547c Reformat various code. 2022-03-29 14:58:06 +02:00
James Cole
1209c4e76a Reformat various code. 2022-03-29 14:56:27 +02:00
James Cole
9cdaf7076a Add copyright statements 2022-03-29 14:55:51 +02:00
James Cole
2a1738cbe1 Update translations. 2022-03-29 14:53:44 +02:00
James Cole
09bd0b572a Make email messages Markdown. 2022-03-29 12:45:48 +02:00
James Cole
9c19a08b17 Defaul empty stateful domains. 2022-03-28 19:54:44 +02:00
James Cole
37f05338f7 First new translations. 2022-03-28 18:59:07 +02:00
James Cole
a72af79fab Fix type error 2022-03-28 12:32:39 +02:00
James Cole
2dfd230918 Merge branch 'develop' into 5.7.0 2022-03-28 12:28:20 +02:00
James Cole
409c24d45a Merge branch 'main' into develop 2022-03-28 12:27:45 +02:00
James Cole
35e187be77 Update packages. 2022-03-28 12:27:15 +02:00
James Cole
df78ef1c78 Merge pull request #5939 from firefly-iii/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-03-28 12:27:08 +02:00
James Cole
d978838c84 Merge branch 'develop' into 5.7.0
# Conflicts:
#	composer.lock
2022-03-28 12:26:38 +02:00
dependabot[bot]
3320e06f81 Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 10:26:33 +00:00
James Cole
ab50a6518b Merge branch 'main' into develop 2022-03-28 12:26:09 +02:00
James Cole
e1155328b8 Merge pull request #5938 from firefly-iii/dependabot/composer/develop/doctrine/dbal-3.3.4
Bump doctrine/dbal from 3.3.3 to 3.3.4
2022-03-28 12:25:25 +02:00
James Cole
daa6ddc39f Merge pull request #5937 from firefly-iii/dependabot/composer/develop/ramsey/uuid-4.3.1
Bump ramsey/uuid from 4.2.3 to 4.3.1
2022-03-28 12:25:13 +02:00
James Cole
3b1ffc87bc Merge pull request #5928 from firefly-iii/dependabot/npm_and_yarn/frontend/node-forge-1.3.0
Bump node-forge from 1.2.1 to 1.3.0 in /frontend
2022-03-28 12:24:47 +02:00
James Cole
94be254367 Merge pull request #5927 from firefly-iii/dependabot/npm_and_yarn/node-forge-1.3.0
Bump node-forge from 1.2.1 to 1.3.0
2022-03-28 12:24:37 +02:00
James Cole
abb1095cef Fix summary and dates, also fix #5770 2022-03-28 12:24:16 +02:00
James Cole
f2849c8058 New cron job for bills. 2022-03-28 12:23:46 +02:00
James Cole
e5a08d2cf1 Search in attachment file names and attachments notes. 2022-03-28 07:54:52 +02:00
dependabot[bot]
46e01475fc Bump doctrine/dbal from 3.3.3 to 3.3.4
Bumps [doctrine/dbal](https://github.com/doctrine/dbal) from 3.3.3 to 3.3.4.
- [Release notes](https://github.com/doctrine/dbal/releases)
- [Commits](https://github.com/doctrine/dbal/compare/3.3.3...3.3.4)

---
updated-dependencies:
- dependency-name: doctrine/dbal
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 03:00:49 +00:00
dependabot[bot]
89c1a2d912 Bump ramsey/uuid from 4.2.3 to 4.3.1
Bumps [ramsey/uuid](https://github.com/ramsey/uuid) from 4.2.3 to 4.3.1.
- [Release notes](https://github.com/ramsey/uuid/releases)
- [Changelog](https://github.com/ramsey/uuid/blob/4.x/CHANGELOG.md)
- [Commits](https://github.com/ramsey/uuid/compare/4.2.3...4.3.1)

---
updated-dependencies:
- dependency-name: ramsey/uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 03:00:43 +00:00
James Cole
2be7813a67 Replace deprecated function. 2022-03-27 20:33:25 +02:00
James Cole
cbf14f541c Replace deprecated method. 2022-03-27 20:24:13 +02:00
James Cole
8ee4c2ea11 Piggies can have no target amount. 2022-03-27 18:30:46 +02:00
James Cole
980120f1bd Update search. 2022-03-27 16:03:50 +02:00
James Cole
679e72e5e2 Make it possible to search by interest date. 2022-03-27 08:48:30 +02:00
James Cole
ff7f4e5bba Merge branch 'develop' into 5.7.0 2022-03-27 06:54:15 +02:00
James Cole
582c6676c6 Rebuild and update. 2022-03-26 18:15:05 +01:00
James Cole
8002610234 Fix amounts with "e" in them. 2022-03-26 18:13:02 +01:00
dependabot[bot]
3ba81c6254 Bump node-forge from 1.2.1 to 1.3.0 in /frontend
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-26 04:34:08 +00:00
dependabot[bot]
dc16a1a430 Bump node-forge from 1.2.1 to 1.3.0
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-26 00:00:16 +00:00
James Cole
2f50fb38b0 New search opts 2022-03-24 19:34:32 +01:00
James Cole
aca008c911 Expand query search. 2022-03-21 06:31:38 +01:00
James Cole
ad0dcc2cf4 Merge branch 'develop' into 5.7.0 2022-03-21 06:25:00 +01:00
James Cole
be1d5591c4 Continue work on search 2022-03-21 06:24:40 +01:00
James Cole
bb57015004 Merge pull request #5919 from firefly-iii/dependabot/npm_and_yarn/develop/postcss-8.4.12
Bump postcss from 8.4.8 to 8.4.12
2022-03-21 05:15:41 +00:00
James Cole
96f7047989 Merge pull request #5918 from firefly-iii/dependabot/composer/develop/guzzlehttp/guzzle-7.4.2
Bump guzzlehttp/guzzle from 7.4.1 to 7.4.2
2022-03-21 05:15:34 +00:00
dependabot[bot]
25e6114948 Bump postcss from 8.4.8 to 8.4.12
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.8 to 8.4.12.
- [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.8...8.4.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-21 03:01:44 +00:00
dependabot[bot]
0ac4a42351 Bump guzzlehttp/guzzle from 7.4.1 to 7.4.2
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.4.1 to 7.4.2.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/master/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.4.1...7.4.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-21 03:00:35 +00:00
James Cole
02687dfe53 Expand search 2022-03-20 17:11:33 +01:00
James Cole
ba10aa5ca5 Move search operators to dedicated file and add lots of new ones. 2022-03-20 07:42:39 +01:00
James Cole
c000e090fe Add environment variable for https://github.com/firefly-iii/firefly-iii/issues/5648 2022-03-19 17:11:12 +01:00
James Cole
9c0893c093 Update version 2022-03-19 11:40:06 +01:00
James Cole
1e1aa28ab2 Add notes to budget https://github.com/firefly-iii/firefly-iii/issues/5373 2022-03-19 11:38:02 +01:00
James Cole
52a5995bd1 Remove LDAP support. 2022-03-19 11:19:58 +01:00
James Cole
5ca0a9f75a Update packages and various code for laravel 9 2022-03-19 08:10:42 +01:00
James Cole
45d99aa456 Merge branch 'develop' into 5.7.0
# Conflicts:
#	composer.json
#	composer.lock
2022-03-19 07:58:06 +01:00
James Cole
39eeea9c3c Fix https://github.com/firefly-iii/firefly-iii/issues/5882 2022-03-19 07:56:41 +01:00
James Cole
55a6cc5cd4 Fix https://github.com/firefly-iii/firefly-iii/issues/5852 2022-03-19 07:34:09 +01:00
James Cole
e3ecfdfac6 Add debug info 2022-03-19 07:14:20 +01:00
James Cole
3ddbb282d7 refer to another authentication guard. 2022-03-19 06:54:48 +01:00
James Cole
346478622b Fix link to docs. 2022-03-17 19:36:13 +01:00
James Cole
fcb9e76c17 Fix https://github.com/firefly-iii/firefly-iii/issues/5903 2022-03-17 16:44:24 +01:00
James Cole
bbcd86eab5 Merge pull request #5897 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-9.5.19
Bump phpunit/phpunit from 9.5.17 to 9.5.19
2022-03-15 18:10:04 +00:00
James Cole
24a6f5f36c Merge pull request #5896 from firefly-iii/dependabot/composer/develop/league/fractal-0.20
Bump league/fractal from 0.19.2 to 0.20
2022-03-15 18:09:52 +00:00
James Cole
6e18b8056d Merge pull request #5898 from firefly-iii/dependabot/composer/develop/doctrine/dbal-3.3.3
Bump doctrine/dbal from 3.3.2 to 3.3.3
2022-03-15 18:09:41 +00:00
dependabot[bot]
1e5137e5db Bump phpunit/phpunit from 9.5.17 to 9.5.19
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.17 to 9.5.19.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.17...9.5.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-15 18:04:00 +00:00
dependabot[bot]
78342537a0 Bump league/fractal from 0.19.2 to 0.20
Bumps [league/fractal](https://github.com/thephpleague/fractal) from 0.19.2 to 0.20.
- [Release notes](https://github.com/thephpleague/fractal/releases)
- [Changelog](https://github.com/thephpleague/fractal/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thephpleague/fractal/compare/0.19.2...0.20)

---
updated-dependencies:
- dependency-name: league/fractal
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-15 18:03:25 +00:00
dependabot[bot]
b20e736f41 Bump doctrine/dbal from 3.3.2 to 3.3.3
Bumps [doctrine/dbal](https://github.com/doctrine/dbal) from 3.3.2 to 3.3.3.
- [Release notes](https://github.com/doctrine/dbal/releases)
- [Commits](https://github.com/doctrine/dbal/compare/3.3.2...3.3.3)

---
updated-dependencies:
- dependency-name: doctrine/dbal
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-15 18:03:15 +00:00
James Cole
df65f08dec Merge pull request #5888 from firefly-iii/dependabot/composer/develop/bacon/bacon-qr-code-2.0.7
Bump bacon/bacon-qr-code from 2.0.6 to 2.0.7
2022-03-15 18:03:11 +00:00
James Cole
03b6f6fcb1 Merge pull request #5889 from firefly-iii/dependabot/composer/develop/laravel/passport-10.3.3
Bump laravel/passport from 10.3.2 to 10.3.3
2022-03-15 18:02:49 +00:00
dependabot[bot]
5c30981e76 Bump laravel/passport from 10.3.2 to 10.3.3
Bumps [laravel/passport](https://github.com/laravel/passport) from 10.3.2 to 10.3.3.
- [Release notes](https://github.com/laravel/passport/releases)
- [Changelog](https://github.com/laravel/passport/blob/10.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/passport/compare/v10.3.2...v10.3.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-15 18:02:42 +00:00
dependabot[bot]
0b2ca03848 Bump bacon/bacon-qr-code from 2.0.6 to 2.0.7
Bumps [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/Bacon/BaconQrCode/releases)
- [Changelog](https://github.com/Bacon/BaconQrCode/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Bacon/BaconQrCode/compare/2.0.6...2.0.7)

---
updated-dependencies:
- dependency-name: bacon/bacon-qr-code
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-15 18:02:37 +00:00
James Cole
70041e713e Merge pull request #5890 from firefly-iii/dependabot/composer/develop/laravel/framework-8.83.4
Bump laravel/framework from 8.83.3 to 8.83.4
2022-03-15 18:02:23 +00:00
James Cole
31625cad4b Merge pull request #5891 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-9.5.18
Bump phpunit/phpunit from 9.5.17 to 9.5.18
2022-03-15 18:02:09 +00:00
James Cole
8663c877af Merge pull request #5892 from firefly-iii/dependabot/composer/develop/rcrowe/twigbridge-0.14.0
Bump rcrowe/twigbridge from 0.13.1 to 0.14.0
2022-03-15 18:01:53 +00:00
James Cole
f76ce602ce Merge pull request #5894 from firefly-iii/dependabot/npm_and_yarn/develop/axios-0.26.1
Bump axios from 0.26.0 to 0.26.1
2022-03-15 18:01:22 +00:00
dependabot[bot]
32d1554fbe Bump axios from 0.26.0 to 0.26.1
Bumps [axios](https://github.com/axios/axios) from 0.26.0 to 0.26.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.26.0...v0.26.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 03:02:11 +00:00
dependabot[bot]
7c28b47f91 Bump rcrowe/twigbridge from 0.13.1 to 0.14.0
Bumps [rcrowe/twigbridge](https://github.com/rcrowe/TwigBridge) from 0.13.1 to 0.14.0.
- [Release notes](https://github.com/rcrowe/TwigBridge/releases)
- [Changelog](https://github.com/rcrowe/TwigBridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rcrowe/TwigBridge/compare/v0.13.1...v0.14.0)

---
updated-dependencies:
- dependency-name: rcrowe/twigbridge
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 03:00:58 +00:00
dependabot[bot]
ff249a4ee6 Bump phpunit/phpunit from 9.5.17 to 9.5.18
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.17 to 9.5.18.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.17...9.5.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 03:00:51 +00:00
dependabot[bot]
a5c75e6abe Bump laravel/framework from 8.83.3 to 8.83.4
Bumps [laravel/framework](https://github.com/laravel/framework) from 8.83.3 to 8.83.4.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/9.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v8.83.3...v8.83.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 03:00:46 +00:00
James Cole
b8a8ddf23e Update translations 2022-03-10 18:00:10 +01:00
James Cole
43c52daf6b Clean up debug page. 2022-03-10 17:59:30 +01:00
James Cole
f0265b9fda Fix https://github.com/firefly-iii/firefly-iii/issues/5870 2022-03-10 17:58:43 +01:00
James Cole
07813fa858 Possible fix for #5869 2022-03-10 17:57:43 +01:00
James Cole
ca7c86a057 Merge pull request #5858 from firefly-iii/dependabot/npm_and_yarn/develop/postcss-8.4.8
Bump postcss from 8.4.7 to 8.4.8
2022-03-07 04:46:39 +00:00
James Cole
c59ccb1077 Merge pull request #5856 from firefly-iii/dependabot/composer/develop/laravel/framework-8.83.3
Bump laravel/framework from 8.83.2 to 8.83.3
2022-03-07 04:46:10 +00:00
James Cole
2ab45ac5d4 Merge pull request #5855 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-9.5.17
Bump phpunit/phpunit from 9.5.16 to 9.5.17
2022-03-07 04:46:00 +00:00
James Cole
ae6b177a08 Merge pull request #5854 from firefly-iii/dependabot/composer/develop/barryvdh/laravel-ide-helper-2.12.3
Bump barryvdh/laravel-ide-helper from 2.12.2 to 2.12.3
2022-03-07 04:45:48 +00:00
dependabot[bot]
50806ace32 Bump postcss from 8.4.7 to 8.4.8
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.7 to 8.4.8.
- [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.7...8.4.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 03:02:16 +00:00
dependabot[bot]
efb0dc42ff Bump laravel/framework from 8.83.2 to 8.83.3
Bumps [laravel/framework](https://github.com/laravel/framework) from 8.83.2 to 8.83.3.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/9.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v8.83.2...v8.83.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 03:00:54 +00:00
dependabot[bot]
2fbeef95f1 Bump phpunit/phpunit from 9.5.16 to 9.5.17
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.16 to 9.5.17.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.16...9.5.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 03:00:45 +00:00
dependabot[bot]
f02d524e82 Bump barryvdh/laravel-ide-helper from 2.12.2 to 2.12.3
Bumps [barryvdh/laravel-ide-helper](https://github.com/barryvdh/laravel-ide-helper) from 2.12.2 to 2.12.3.
- [Release notes](https://github.com/barryvdh/laravel-ide-helper/releases)
- [Changelog](https://github.com/barryvdh/laravel-ide-helper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/barryvdh/laravel-ide-helper/compare/v2.12.2...v2.12.3)

---
updated-dependencies:
- dependency-name: barryvdh/laravel-ide-helper
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 03:00:40 +00:00
James Cole
6479fbabed Catch account 2022-03-06 20:08:55 +01:00
James Cole
059bf32563 Include headers in error message. 2022-03-06 16:03:52 +01:00
James Cole
2f55499f7d Fix call. 2022-03-06 15:47:11 +01:00
James Cole
9c8bcd4f4c Merge branch 'main' into develop 2022-03-06 11:44:07 +01:00
James Cole
2715a181e3 Add debug 2022-03-06 11:43:25 +01:00
James Cole
b3c831d596 Merge pull request #5831 from firefly-iii/dependabot/npm_and_yarn/frontend/nanoid-3.3.1
Bump nanoid from 3.1.30 to 3.3.1 in /frontend
2022-03-04 04:44:54 +00:00
James Cole
274885c8a6 Merge pull request #5832 from firefly-iii/dependabot/npm_and_yarn/frontend/follow-redirects-1.14.9
Bump follow-redirects from 1.14.6 to 1.14.9 in /frontend
2022-03-04 04:44:41 +00:00
James Cole
d6e5f71d50 Clean up destroy routine 2022-02-28 17:06:43 +01:00
James Cole
b9536dfe4e Clean up destroy routine 2022-02-28 17:06:01 +01:00
James Cole
22a6e34279 Fix #5810 2022-02-28 09:11:08 +01:00
James Cole
b1a68b087c Merge tag '5.6.16' into develop
5.6.16
2022-02-28 09:01:01 +01:00
James Cole
ef8f9672af Merge branch 'release/5.6.16' 2022-02-28 09:00:56 +01:00
James Cole
b696b09f92 New meta files for release. 2022-02-28 09:00:33 +01:00
James Cole
9892e70028 Rename file. 2022-02-28 08:53:12 +01:00
James Cole
52f885df20 Rename migration so it doesn't clash. 2022-02-28 08:47:58 +01:00
James Cole
a58c6b0cec Do not search for empty number. 2022-02-28 08:31:58 +01:00
James Cole
b59723f276 Update meta files for 5.7.0 #5757 2022-02-28 07:48:58 +01:00
dependabot[bot]
20ab27b237 Bump nanoid from 3.1.30 to 3.3.1 in /frontend
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.30 to 3.3.1.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.30...3.3.1)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 06:11:28 +00:00
dependabot[bot]
046d7befca Bump follow-redirects from 1.14.6 to 1.14.9 in /frontend
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.6 to 1.14.9.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.6...v1.14.9)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 06:11:28 +00:00
James Cole
a8cbbde8fc Merge branch 'release/5.6.15'
# Conflicts:
#	yarn.lock
2022-02-28 07:10:43 +01:00
James Cole
efb7d4275d Update meta files for new release. 2022-02-28 06:40:34 +01:00
mergify[bot]
d4f275e566 Merge pull request #5829 from firefly-iii/dependabot/npm_and_yarn/develop/postcss-8.4.7
Bump postcss from 8.4.6 to 8.4.7
2022-02-28 03:02:15 +00:00
mergify[bot]
45db911011 Merge pull request #5828 from firefly-iii/dependabot/npm_and_yarn/develop/bootstrap-sass-3.4.2
Bump bootstrap-sass from 3.4.1 to 3.4.2
2022-02-28 03:02:11 +00:00
dependabot[bot]
50fccec438 Bump postcss from 8.4.6 to 8.4.7
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.6 to 8.4.7.
- [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.6...8.4.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:02:02 +00:00
dependabot[bot]
67e72e864c Bump bootstrap-sass from 3.4.1 to 3.4.2
Bumps [bootstrap-sass](https://github.com/twbs/bootstrap-sass) from 3.4.1 to 3.4.2.
- [Release notes](https://github.com/twbs/bootstrap-sass/releases)
- [Changelog](https://github.com/twbs/bootstrap-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/twbs/bootstrap-sass/compare/v3.4.1...v3.4.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:01:53 +00:00
mergify[bot]
dff4946b48 Merge pull request #5827 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-9.5.16
Bump phpunit/phpunit from 9.5.14 to 9.5.16
2022-02-28 03:01:31 +00:00
mergify[bot]
a38700f3fa Merge pull request #5826 from firefly-iii/dependabot/composer/develop/laravel/framework-8.83.2
Bump laravel/framework from 8.83.1 to 8.83.2
2022-02-28 03:01:26 +00:00
mergify[bot]
42c4441755 Merge pull request #5825 from firefly-iii/dependabot/composer/develop/league/commonmark-2.2.3
Bump league/commonmark from 2.2.2 to 2.2.3
2022-02-28 03:01:23 +00:00
mergify[bot]
1a4b646acd Merge pull request #5824 from firefly-iii/dependabot/composer/develop/laravel/sanctum-2.14.2
Bump laravel/sanctum from 2.14.1 to 2.14.2
2022-02-28 03:01:19 +00:00
mergify[bot]
5888dd38a2 Merge pull request #5823 from firefly-iii/dependabot/composer/develop/laravel/ui-3.4.5
Bump laravel/ui from 3.4.4 to 3.4.5
2022-02-28 03:01:15 +00:00
dependabot[bot]
f56d63c754 Bump phpunit/phpunit from 9.5.14 to 9.5.16
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.14 to 9.5.16.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.14...9.5.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:01:06 +00:00
dependabot[bot]
93db50383a Bump laravel/framework from 8.83.1 to 8.83.2
Bumps [laravel/framework](https://github.com/laravel/framework) from 8.83.1 to 8.83.2.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/9.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v8.83.1...v8.83.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:01:02 +00:00
dependabot[bot]
4e9b5a71db Bump league/commonmark from 2.2.2 to 2.2.3
Bumps [league/commonmark](https://github.com/thephpleague/commonmark) from 2.2.2 to 2.2.3.
- [Release notes](https://github.com/thephpleague/commonmark/releases)
- [Changelog](https://github.com/thephpleague/commonmark/blob/2.2/CHANGELOG.md)
- [Commits](https://github.com/thephpleague/commonmark/compare/2.2.2...2.2.3)

---
updated-dependencies:
- dependency-name: league/commonmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:00:53 +00:00
dependabot[bot]
c85be915e6 Bump laravel/sanctum from 2.14.1 to 2.14.2
Bumps [laravel/sanctum](https://github.com/laravel/sanctum) from 2.14.1 to 2.14.2.
- [Release notes](https://github.com/laravel/sanctum/releases)
- [Changelog](https://github.com/laravel/sanctum/blob/2.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/sanctum/compare/v2.14.1...v2.14.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:00:47 +00:00
dependabot[bot]
1df4cdda42 Bump laravel/ui from 3.4.4 to 3.4.5
Bumps [laravel/ui](https://github.com/laravel/ui) from 3.4.4 to 3.4.5.
- [Release notes](https://github.com/laravel/ui/releases)
- [Changelog](https://github.com/laravel/ui/blob/3.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/ui/compare/v3.4.4...v3.4.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 03:00:41 +00:00
James Cole
cad03b04ae Initial build. 2022-02-27 10:16:34 +01:00
James Cole
cddfa3a8d2 Router and store 2022-02-27 10:14:26 +01:00
James Cole
3a49af94d0 Initial set of pages. 2022-02-27 10:14:08 +01:00
James Cole
e60320a9be Main layout 2022-02-27 10:13:55 +01:00
James Cole
0ffb3508c6 Support for languages 2022-02-27 10:13:43 +01:00
James Cole
d618f6d355 CSS 2022-02-27 10:13:31 +01:00
James Cole
e542a65bf3 Various components 2022-02-27 10:13:25 +01:00
James Cole
d1e1314dcf boot code 2022-02-27 10:13:16 +01:00
James Cole
9ebdb00579 API code 2022-02-27 10:13:07 +01:00
James Cole
95a7a0c90d Root source 2022-02-27 10:12:54 +01:00
James Cole
cabd3d60f0 Icons and other meta files. 2022-02-27 10:12:38 +01:00
James Cole
ab8ee8b72a Config files related to new layout. 2022-02-27 10:04:43 +01:00
James Cole
01f06a7e5b Meta files related to new layout. 2022-02-27 10:04:30 +01:00
James Cole
aa7d4a610b Add files and updates necessary to manage new layout. 2022-02-27 10:04:08 +01:00
James Cole
3f61b6d707 Clean up git ignore. 2022-02-27 09:52:08 +01:00
James Cole
9ae0cc5700 Clean up git ignore. 2022-02-27 09:51:54 +01:00
James Cole
6f65a73dd9 Add migration, update languages. 2022-02-26 11:24:16 +01:00
James Cole
fb676a9ad7 Update languages, config. 2022-02-26 07:55:36 +01:00
James Cole
dd66a1adf0 Fix https://github.com/firefly-iii/firefly-iii/issues/5810 2022-02-23 10:52:24 +01:00
James Cole
8c9bb3addb Tiny fixes in API 2022-02-23 06:33:27 +01:00
James Cole
472c1a0c37 Fix string conversion error. 2022-02-21 19:53:49 +01:00
James Cole
6fe8bf6c41 Update recurrence API 2022-02-21 16:48:26 +01:00
James Cole
342e6f2fef Fix https://github.com/firefly-iii/firefly-iii/issues/5806 2022-02-21 16:48:16 +01:00
mergify[bot]
23a8e3ef41 Merge pull request #5805 from firefly-iii/dependabot/npm_and_yarn/develop/vue-i18n-9.1.9
Bump vue-i18n from 8.27.0 to 9.1.9
2022-02-21 03:04:32 +00:00
dependabot[bot]
7c11b99469 Bump vue-i18n from 8.27.0 to 9.1.9
Bumps [vue-i18n](https://github.com/intlify/vue-i18n-next/tree/HEAD/packages/vue-i18n) from 8.27.0 to 9.1.9.
- [Release notes](https://github.com/intlify/vue-i18n-next/releases)
- [Changelog](https://github.com/intlify/vue-i18n-next/blob/v9.1.9/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n-next/commits/v9.1.9/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:04:01 +00:00
mergify[bot]
e715162ed6 Merge pull request #5804 from firefly-iii/dependabot/npm_and_yarn/develop/laravel-mix-6.0.43
Bump laravel-mix from 6.0.42 to 6.0.43
2022-02-21 03:02:53 +00:00
mergify[bot]
368cc550cb Merge pull request #5803 from firefly-iii/dependabot/npm_and_yarn/develop/uiv-2.0.0
Bump uiv from 1.4.1 to 2.0.0
2022-02-21 03:02:49 +00:00
dependabot[bot]
60311341e0 Bump laravel-mix from 6.0.42 to 6.0.43
Bumps [laravel-mix](https://github.com/JeffreyWay/laravel-mix) from 6.0.42 to 6.0.43.
- [Release notes](https://github.com/JeffreyWay/laravel-mix/releases)
- [Changelog](https://github.com/laravel-mix/laravel-mix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JeffreyWay/laravel-mix/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:02:27 +00:00
dependabot[bot]
749ebd9cc4 Bump uiv from 1.4.1 to 2.0.0
Bumps [uiv](https://github.com/uiv-lib/uiv) from 1.4.1 to 2.0.0.
- [Release notes](https://github.com/uiv-lib/uiv/releases)
- [Commits](https://github.com/uiv-lib/uiv/compare/v1.4.1...v2.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:02:16 +00:00
mergify[bot]
c699a14a35 Merge pull request #5802 from firefly-iii/dependabot/composer/develop/laravel/ui-3.4.4
Bump laravel/ui from 3.4.3 to 3.4.4
2022-02-21 03:01:30 +00:00
mergify[bot]
b05a2d385c Merge pull request #5801 from firefly-iii/dependabot/composer/develop/laravel/sanctum-2.14.1
Bump laravel/sanctum from 2.14.0 to 2.14.1
2022-02-21 03:01:27 +00:00
mergify[bot]
7c78d19e3a Merge pull request #5800 from firefly-iii/dependabot/composer/develop/laravel/framework-8.83.1
Bump laravel/framework from 8.83.0 to 8.83.1
2022-02-21 03:01:22 +00:00
mergify[bot]
8632307cb1 Merge pull request #5799 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-9.5.14
Bump phpunit/phpunit from 9.5.13 to 9.5.14
2022-02-21 03:01:19 +00:00
dependabot[bot]
5a18f3ce4a Bump laravel/ui from 3.4.3 to 3.4.4
Bumps [laravel/ui](https://github.com/laravel/ui) from 3.4.3 to 3.4.4.
- [Release notes](https://github.com/laravel/ui/releases)
- [Changelog](https://github.com/laravel/ui/blob/3.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/ui/compare/v3.4.3...v3.4.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:01:07 +00:00
dependabot[bot]
1258aff0b4 Bump laravel/sanctum from 2.14.0 to 2.14.1
Bumps [laravel/sanctum](https://github.com/laravel/sanctum) from 2.14.0 to 2.14.1.
- [Release notes](https://github.com/laravel/sanctum/releases)
- [Changelog](https://github.com/laravel/sanctum/blob/2.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/sanctum/compare/v2.14.0...v2.14.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:01:01 +00:00
dependabot[bot]
b0904c11a0 Bump laravel/framework from 8.83.0 to 8.83.1
Bumps [laravel/framework](https://github.com/laravel/framework) from 8.83.0 to 8.83.1.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/9.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v8.83.0...v8.83.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:00:53 +00:00
dependabot[bot]
ca517eb4d9 Bump phpunit/phpunit from 9.5.13 to 9.5.14
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.13 to 9.5.14.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.13...9.5.14)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 03:00:45 +00:00
James Cole
c522dd2931 Update security.txt and associated key. 2022-02-19 07:28:13 +01:00
James Cole
7399edee2e Use dropIfExists 2022-02-19 05:20:42 +01:00
James Cole
ec93b7b5a0 Fix https://github.com/firefly-iii/firefly-iii/issues/5694 2022-02-17 19:22:58 +01:00
James Cole
280762fff3 Make sure fields are named properly 2022-02-17 19:03:54 +01:00
James Cole
b733fa2961 Update mandatory fields. 2022-02-17 19:03:41 +01:00
James Cole
5176f8bdc2 Add instructions. 2022-02-17 19:03:31 +01:00
mergify[bot]
91d96b2f0e Merge pull request #5784 from firefly-iii/dependabot/npm_and_yarn/develop/vue-3.2.31
Bump vue from 2.6.14 to 3.2.31
2022-02-14 03:03:30 +00:00
mergify[bot]
c3229e597c Merge pull request #5785 from firefly-iii/dependabot/npm_and_yarn/develop/axios-0.26.0
Bump axios from 0.25.0 to 0.26.0
2022-02-14 03:03:25 +00:00
dependabot[bot]
0f371bc5a9 Bump vue from 2.6.14 to 3.2.31
Bumps [vue](https://github.com/vuejs/core) from 2.6.14 to 3.2.31.
- [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.2.31)

---
updated-dependencies:
- dependency-name: vue
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:03:16 +00:00
dependabot[bot]
297d5940ce Bump axios from 0.25.0 to 0.26.0
Bumps [axios](https://github.com/axios/axios) from 0.25.0 to 0.26.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:02:52 +00:00
mergify[bot]
3b27ceaf53 Merge pull request #5783 from firefly-iii/dependabot/npm_and_yarn/develop/laravel-mix-6.0.42
Bump laravel-mix from 6.0.41 to 6.0.42
2022-02-14 03:02:44 +00:00
dependabot[bot]
d9142c1197 Bump laravel-mix from 6.0.41 to 6.0.42
Bumps [laravel-mix](https://github.com/JeffreyWay/laravel-mix) from 6.0.41 to 6.0.42.
- [Release notes](https://github.com/JeffreyWay/laravel-mix/releases)
- [Changelog](https://github.com/laravel-mix/laravel-mix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JeffreyWay/laravel-mix/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:02:36 +00:00
mergify[bot]
9b3d1160d6 Merge pull request #5781 from firefly-iii/dependabot/npm_and_yarn/develop/vue-loader-17.0.0
Bump vue-loader from 15.9.8 to 17.0.0
2022-02-14 03:02:05 +00:00
dependabot[bot]
05d144c279 Bump vue-loader from 15.9.8 to 17.0.0
Bumps [vue-loader](https://github.com/vuejs/vue-loader) from 15.9.8 to 17.0.0.
- [Release notes](https://github.com/vuejs/vue-loader/releases)
- [Changelog](https://github.com/vuejs/vue-loader/blob/next/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-loader/commits)

---
updated-dependencies:
- dependency-name: vue-loader
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:02:01 +00:00
mergify[bot]
a318b66854 Merge pull request #5780 from firefly-iii/dependabot/composer/develop/laravel/ui-3.4.3
Bump laravel/ui from 3.4.2 to 3.4.3
2022-02-14 03:02:00 +00:00
mergify[bot]
431eef5e80 Merge pull request #5779 from firefly-iii/dependabot/composer/develop/barryvdh/laravel-debugbar-3.6.7
Bump barryvdh/laravel-debugbar from 3.6.6 to 3.6.7
2022-02-14 03:01:54 +00:00
dependabot[bot]
a8d20c5a01 Bump laravel/ui from 3.4.2 to 3.4.3
Bumps [laravel/ui](https://github.com/laravel/ui) from 3.4.2 to 3.4.3.
- [Release notes](https://github.com/laravel/ui/releases)
- [Changelog](https://github.com/laravel/ui/blob/3.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/ui/compare/v3.4.2...v3.4.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:01:49 +00:00
mergify[bot]
676d75646e Merge pull request #5778 from firefly-iii/dependabot/composer/develop/barryvdh/laravel-ide-helper-2.12.2
Bump barryvdh/laravel-ide-helper from 2.12.1 to 2.12.2
2022-02-14 03:01:48 +00:00
mergify[bot]
6cbc438aa0 Merge pull request #5777 from firefly-iii/dependabot/composer/develop/laravel/framework-8.83.0
Bump laravel/framework from 8.82.0 to 8.83.0
2022-02-14 03:01:43 +00:00
dependabot[bot]
4a8913c98c Bump barryvdh/laravel-debugbar from 3.6.6 to 3.6.7
Bumps [barryvdh/laravel-debugbar](https://github.com/barryvdh/laravel-debugbar) from 3.6.6 to 3.6.7.
- [Release notes](https://github.com/barryvdh/laravel-debugbar/releases)
- [Changelog](https://github.com/barryvdh/laravel-debugbar/blob/master/changelog.md)
- [Commits](https://github.com/barryvdh/laravel-debugbar/compare/v3.6.6...v3.6.7)

---
updated-dependencies:
- dependency-name: barryvdh/laravel-debugbar
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:01:40 +00:00
mergify[bot]
9d1ecd845a Merge pull request #5776 from firefly-iii/dependabot/composer/develop/league/commonmark-2.2.2
Bump league/commonmark from 2.2.1 to 2.2.2
2022-02-14 03:01:39 +00:00
mergify[bot]
16987aca71 Merge pull request #5775 from firefly-iii/dependabot/composer/develop/rcrowe/twigbridge-0.13.1
Bump rcrowe/twigbridge from 0.13.0 to 0.13.1
2022-02-14 03:01:34 +00:00
mergify[bot]
445e8d7838 Merge pull request #5774 from firefly-iii/dependabot/composer/develop/laravelcollective/html-6.3.0
Bump laravelcollective/html from 6.2.1 to 6.3.0
2022-02-14 03:01:30 +00:00
dependabot[bot]
e521d5dcd0 Bump barryvdh/laravel-ide-helper from 2.12.1 to 2.12.2
Bumps [barryvdh/laravel-ide-helper](https://github.com/barryvdh/laravel-ide-helper) from 2.12.1 to 2.12.2.
- [Release notes](https://github.com/barryvdh/laravel-ide-helper/releases)
- [Changelog](https://github.com/barryvdh/laravel-ide-helper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/barryvdh/laravel-ide-helper/compare/v2.12.1...v2.12.2)

---
updated-dependencies:
- dependency-name: barryvdh/laravel-ide-helper
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:01:29 +00:00
dependabot[bot]
a4ed85d33b Bump laravel/framework from 8.82.0 to 8.83.0
Bumps [laravel/framework](https://github.com/laravel/framework) from 8.82.0 to 8.83.0.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/9.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v8.82.0...v8.83.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>
2022-02-14 03:01:23 +00:00
dependabot[bot]
65e8a7fed6 Bump league/commonmark from 2.2.1 to 2.2.2
Bumps [league/commonmark](https://github.com/thephpleague/commonmark) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/thephpleague/commonmark/releases)
- [Changelog](https://github.com/thephpleague/commonmark/blob/2.2/CHANGELOG.md)
- [Commits](https://github.com/thephpleague/commonmark/compare/2.2.1...2.2.2)

---
updated-dependencies:
- dependency-name: league/commonmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:01:09 +00:00
dependabot[bot]
1052a19262 Bump rcrowe/twigbridge from 0.13.0 to 0.13.1
Bumps [rcrowe/twigbridge](https://github.com/rcrowe/TwigBridge) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/rcrowe/TwigBridge/releases)
- [Changelog](https://github.com/rcrowe/TwigBridge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rcrowe/TwigBridge/compare/v0.13.0...v0.13.1)

---
updated-dependencies:
- dependency-name: rcrowe/twigbridge
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:01:04 +00:00
dependabot[bot]
a2b7a5f1f0 Bump laravelcollective/html from 6.2.1 to 6.3.0
Bumps [laravelcollective/html](https://github.com/LaravelCollective/html) from 6.2.1 to 6.3.0.
- [Release notes](https://github.com/LaravelCollective/html/releases)
- [Commits](https://github.com/LaravelCollective/html/compare/v6.2.1...v6.3.0)

---
updated-dependencies:
- dependency-name: laravelcollective/html
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 03:00:54 +00:00
James Cole
9f09872e0f Merge pull request #5765 from firefly-iii/dependabot/npm_and_yarn/follow-redirects-1.14.8
Bump follow-redirects from 1.14.7 to 1.14.8
2022-02-12 10:25:25 +00:00
dependabot[bot]
60ea033064 Bump follow-redirects from 1.14.7 to 1.14.8
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-12 10:05:59 +00:00
James Cole
1f3badb731 Update various routes 2022-02-09 17:31:30 +01:00
James Cole
eb0281e47f Fix code for #5493 as suggested by @tjmv 2022-02-09 11:14:00 +01:00
James Cole
7fc94415fb Update request must also have valid triggers and actions. 2022-02-09 07:50:36 +01:00
James Cole
8dd7d9ba26 Add validation for at least one active action. 2022-02-07 09:42:23 +01:00
James Cole
b9ac43e86d Fix https://github.com/firefly-iii/firefly-iii/issues/5724 2022-02-07 06:20:50 +01:00
James Cole
99a5f827ae Disable webhooks again 2022-02-07 06:19:35 +01:00
James Cole
fbdb7e099c Add new config key 2022-02-07 06:19:27 +01:00
James Cole
6080dabb56 Catch invalid setting 2022-02-07 06:19:19 +01:00
mergify[bot]
cf1540060a Merge pull request #5727 from firefly-iii/dependabot/composer/develop/doctrine/dbal-3.3.2
Bump doctrine/dbal from 3.3.1 to 3.3.2
2022-02-07 03:01:06 +00:00
dependabot[bot]
f96a9f652d Bump doctrine/dbal from 3.3.1 to 3.3.2
Bumps [doctrine/dbal](https://github.com/doctrine/dbal) from 3.3.1 to 3.3.2.
- [Release notes](https://github.com/doctrine/dbal/releases)
- [Commits](https://github.com/doctrine/dbal/compare/3.3.1...3.3.2)

---
updated-dependencies:
- dependency-name: doctrine/dbal
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-07 03:00:32 +00:00
James Cole
d969109e05 Clean up changelog. 2022-02-05 12:53:05 +01:00
James Cole
9a08cf6266 Merge branch 'release/5.6.14' 2022-02-05 09:10:45 +01:00
James Cole
10ea575cd8 Merge tag '5.6.14' into develop
5.6.14
2022-02-05 09:10:45 +01:00
James Cole
356876b2b2 Update meta files for new release. 2022-02-05 09:02:30 +01:00
James Cole
f5197ec2e0 Update meta files for new release. 2022-02-05 08:59:41 +01:00
James Cole
71af5db38e Update meta files for new release. 2022-02-05 08:59:24 +01:00
James Cole
45195e6496 Update version and language strings. 2022-02-05 08:53:58 +01:00
James Cole
a56a6df557 Final changes to bills 2022-02-05 08:53:45 +01:00
James Cole
d7e6a7b125 Fix https://github.com/firefly-iii/firefly-iii/issues/5670 2022-02-03 13:16:20 +01:00
James Cole
ddabfbc1ad Remove references to help 2022-02-03 10:32:20 +01:00
James Cole
944864ed25 Add daily bill period 2022-02-03 06:45:45 +01:00
James Cole
1c795e71d5 Fix https://github.com/firefly-iii/firefly-iii/issues/5695 2022-02-02 20:15:28 +01:00
James Cole
7d7e1366a6 Catch empty string. 2022-02-01 07:14:51 +01:00
mergify[bot]
158a7b1517 Merge pull request #5672 from firefly-iii/dependabot/composer/develop/doctrine/dbal-3.3.1
Bump doctrine/dbal from 3.3.0 to 3.3.1
2022-01-31 03:01:13 +00:00
mergify[bot]
03f19ec235 Merge pull request #5671 from firefly-iii/dependabot/composer/develop/bacon/bacon-qr-code-2.0.5
Bump bacon/bacon-qr-code from 2.0.4 to 2.0.5
2022-01-31 03:01:09 +00:00
dependabot[bot]
a82ec20833 Bump doctrine/dbal from 3.3.0 to 3.3.1
Bumps [doctrine/dbal](https://github.com/doctrine/dbal) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/doctrine/dbal/releases)
- [Commits](https://github.com/doctrine/dbal/compare/3.3.0...3.3.1)

---
updated-dependencies:
- dependency-name: doctrine/dbal
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-31 03:00:40 +00:00
dependabot[bot]
fb8e238319 Bump bacon/bacon-qr-code from 2.0.4 to 2.0.5
Bumps [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) from 2.0.4 to 2.0.5.
- [Release notes](https://github.com/Bacon/BaconQrCode/releases)
- [Changelog](https://github.com/Bacon/BaconQrCode/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Bacon/BaconQrCode/compare/2.0.4...2.0.5)

---
updated-dependencies:
- dependency-name: bacon/bacon-qr-code
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-31 03:00:35 +00:00
James Cole
ab943bf006 Fix https://github.com/firefly-iii/firefly-iii/issues/5666 2022-01-30 19:41:24 +01:00
James Cole
b15b58f099 Fix https://github.com/firefly-iii/firefly-iii/issues/5664 2022-01-30 17:37:44 +01:00
James Cole
fee8d962e3 Fix issues with accounts API https://github.com/firefly-iii/firefly-iii/discussions/5661 2022-01-30 17:17:01 +01:00
James Cole
c0aca0e021 Merge tag '5.6.13' into develop
5.6.13
2022-01-30 17:01:28 +01:00
1215 changed files with 65114 additions and 22780 deletions

View File

@@ -142,7 +142,6 @@ MAIL_ENCRYPTION=null
MAILGUN_DOMAIN= MAILGUN_DOMAIN=
MAILGUN_SECRET= MAILGUN_SECRET=
# If you are on EU region in mailgun, use api.eu.mailgun.net, otherwise use api.mailgun.net # If you are on EU region in mailgun, use api.eu.mailgun.net, otherwise use api.mailgun.net
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE # If you use Docker or similar, you can set this variable from a file by appending it with _FILE
MAILGUN_ENDPOINT=api.mailgun.net MAILGUN_ENDPOINT=api.mailgun.net
@@ -176,42 +175,14 @@ MAP_DEFAULT_ZOOM=6
# #
# Firefly III supports a few authentication methods: # Firefly III supports a few authentication methods:
# - 'web' (default, uses built in DB) # - 'web' (default, uses built in DB)
# - 'ldap'
# - 'remote_user_guard' for Authelia etc # - 'remote_user_guard' for Authelia etc
# Read more about these settings in the documentation. # Read more about these settings in the documentation.
# https://docs.firefly-iii.org/advanced-installation/authentication # https://docs.firefly-iii.org/advanced-installation/authentication
#
# LDAP is no longer supported :(
#
AUTHENTICATION_GUARD=web AUTHENTICATION_GUARD=web
#
# Your LDAP server may speak a dialect. You can choose between 'OpenLDAP' and 'ActiveDirectory'
# Anything else defaults to 'ActiveDirectory'
#
LDAP_DIALECT=OpenLDAP
#
# LDAP connection settings:
#
LDAP_HOST=ldap.yourserver.com
LDAP_PORT=389
LDAP_TIMEOUT=5
LDAP_SSL=false
LDAP_TLS=false
LDAP_BASE_DN="o=something,dc=site,dc=com"
LDAP_USERNAME="uid=X,ou=,o=,dc=something,dc=com"
LDAP_PASSWORD=super_secret
LDAP_AUTH_FIELD=uid
#
# If you wish to only authenticate users from a specific group, use the base DN above.
#
# If you require extra/special filters please use the LDAP_EXTRA_FILTER with a valid DN.
#
# The extra filter will only be applied after the user is authenticated.
#
LDAP_EXTRA_FILTER=
# #
# Remote user guard settings # Remote user guard settings
# #
@@ -254,6 +225,8 @@ ALLOW_WEBHOOKS=false
# #
# For more info: https://docs.firefly-iii.org/firefly-iii/advanced-installation/cron/ # For more info: https://docs.firefly-iii.org/firefly-iii/advanced-installation/cron/
# #
# You can set this variable from a file by appending it with _FILE
#
STATIC_CRON_TOKEN= STATIC_CRON_TOKEN=
# You can fine tune the start-up of a Docker container by editing these environment variables. # You can fine tune the start-up of a Docker container by editing these environment variables.
@@ -261,6 +234,13 @@ STATIC_CRON_TOKEN=
# However if you know what you're doing you can significantly speed up container start times. # However if you know what you're doing you can significantly speed up container start times.
# Set each value to true to enable, or false to disable. # Set each value to true to enable, or false to disable.
# Set this to true to build all locales supported by Firefly III.
# This may take quite some time (several minutes) and is generally not recommended.
# If you wish to change or alter the list of locales, start your Docker container with
# `docker run -v locale.gen:/etc/locale.gen -e DKR_BUILD_LOCALE=true`
# and make sure your preferred locales are in your own locale.gen.
DKR_BUILD_LOCALE=false
# Check if the SQLite database exists. Can be skipped if you're not using SQLite. # Check if the SQLite database exists. Can be skipped if you're not using SQLite.
# Won't significantly speed up things. # Won't significantly speed up things.
DKR_CHECK_SQLITE=true DKR_CHECK_SQLITE=true
@@ -289,7 +269,6 @@ DKR_RUN_PASSPORT_INSTALL=true
# Leave the following configuration vars as is. # Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing. # Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII APP_NAME=FireflyIII
ADLDAP_CONNECTION=default
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
QUEUE_DRIVER=sync QUEUE_DRIVER=sync
CACHE_PREFIX=firefly CACHE_PREFIX=firefly

View File

@@ -1,15 +1,16 @@
# It's not you, it's me # It's not you, it's me
Sometimes bugs reported to Firefly III are configuration and system problems on the user side. Sometimes bugs reported to Firefly III are configuration and system problems on the user's side.
If you run into one of the following problems, there's a good chance it's not a Firefly III issue, but a configuration issue. If you run into any of the following problems, there's a good chance it's not a Firefly III issue, but a configuration issue.
- ⚠️ Can't connect to the database when starting Firefly III - ⚠️ Firefly III can't connect to the database when starting or the password is wrong, even though you're sure it's correct.
- ⚠️ Errors with missing app keys or encryption problems - ⚠️ Errors about a missing `APP_KEY` or other encryption/hash problems
- ⚠️ Can't login due to 419 errors - ⚠️ You can't login due to `419` errors (page expired)
- ⚠️ Any 500 error when starting Firefly III - ⚠️ Any `500` error when starting Firefly III
- ⚠️ Any white page when starting Firefly III - ⚠️ Any white page when starting Firefly III
- ⚠️ Time-out when starting Firefly III for the first time - ⚠️ Time-out when starting Firefly III for the first time
- ⚠️ Firefly III does not work behind your reverse proxy - ⚠️ Firefly III does not work behind your reverse proxy
- ⚠️ You can't connect to the Data Importer due to 404's or authentication issues.
If you run into an issue like this, please start a [discussion](https://github.com/firefly-iii/firefly-iii/discussions) or chat on [Gitter.im](https://gitter.im/firefly-iii/firefly-iii). There's a good chance it's not a bug but something we can fix rather quickly :+1: If you run into an issue like this, please start a [discussion](https://github.com/firefly-iii/firefly-iii/discussions) or chat on [Gitter.im](https://gitter.im/firefly-iii/firefly-iii). There's a good chance it's not a bug but something we can fix rather quickly :+1:

6
.github/mergify.yml vendored
View File

@@ -1,10 +1,4 @@
pull_request_rules: pull_request_rules:
- name: Security update by dependabot
conditions:
- author~=^dependabot(|-preview)\[bot\]$
actions:
merge:
method: merge
- name: Close all on main - name: Close all on main
conditions: conditions:
- base=main - base=main

2
.github/support.md vendored
View File

@@ -25,7 +25,7 @@ Only then [create a new issue](https://github.com/firefly-iii/firefly-iii/issues
## Issue closure and abandonment policy ## Issue closure and abandonment policy
- Issues can be converted into discussions if it's not a bug or feature request. - Issues can be converted into discussions if it's not a bug or feature request.
- Features that won't be implemented will be labelled "wontfix". [This isn't personal](https://docs.firefly-iii.org/firefly-iii/support/features/#ideas-that-wont-be-implemented). - Features that won't be implemented will be labelled "wontfix". [This isn't personal](https://docs.firefly-iii.org/firefly-iii/about-firefly-iii/what-its-not/).
- Issues can be closed if they're duplicates of other issues. - Issues can be closed if they're duplicates of other issues.
- Issues can be closed if the answer is in the FAQ. - Issues can be closed if the answer is in the FAQ.
- Issues will be closed automatically after 14 days. - Issues will be closed automatically after 14 days.

11
.gitignore vendored
View File

@@ -1,19 +1,8 @@
/node_modules /node_modules
/frontend/node_modules /frontend/node_modules
/frontend/fonts
/frontend/images
/public/hot
/public/storage
/storage/*.key /storage/*.key
/vendor /vendor
/.vagrant /.vagrant
Homestead.json
Homestead.yaml
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
.env .env
public/google*.html
report.html
composer.phar
app.js.map
frontend-v3

View File

@@ -70,8 +70,9 @@ class AccountController extends Controller
* @param AutocompleteRequest $request * @param AutocompleteRequest $request
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException
* @throws JsonException * @throws JsonException
* @throws FireflyException
* @throws FireflyException
*/ */
public function accounts(AutocompleteRequest $request): JsonResponse public function accounts(AutocompleteRequest $request): JsonResponse
{ {

View File

@@ -35,6 +35,9 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ApiSupport; use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use JsonException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/** /**
* Class AccountController * Class AccountController
@@ -77,6 +80,9 @@ class AccountController extends Controller
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException * @throws FireflyException
* @throws JsonException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
public function overview(DateRequest $request): JsonResponse public function overview(DateRequest $request): JsonResponse
{ {

View File

@@ -34,6 +34,8 @@ use Illuminate\Routing\Controller as BaseController;
use League\Fractal\Manager; use League\Fractal\Manager;
use League\Fractal\Serializer\JsonApiSerializer; use League\Fractal\Serializer\JsonApiSerializer;
use Log; use Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\ParameterBag;
/** /**
@@ -74,6 +76,8 @@ abstract class Controller extends BaseController
* Method to grab all parameters from the URI. * Method to grab all parameters from the URI.
* *
* @return ParameterBag * @return ParameterBag
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
private function getParameters(): ParameterBag private function getParameters(): ParameterBag
{ {
@@ -94,7 +98,7 @@ abstract class Controller extends BaseController
$obj = Carbon::parse($date); $obj = Carbon::parse($date);
} catch (InvalidDateException | InvalidFormatException $e) { } catch (InvalidDateException | InvalidFormatException $e) {
// don't care // don't care
Log::error(sprintf('Invalid date exception in API controller: %s', $e->getMessage())); Log::warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', $date, $e->getMessage()));
} }
} }
$bag->set($field, $obj); $bag->set($field, $obj);

View File

@@ -209,8 +209,6 @@ class ListController extends Controller
* *
* @param Request $request * @param Request $request
* *
* @param Budget $budget
*
* @return JsonResponse * @return JsonResponse
* @throws FireflyException * @throws FireflyException
* @codeCoverageIgnore * @codeCoverageIgnore

View File

@@ -77,7 +77,7 @@ class ShowController extends Controller
$pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it. // get list of budgets. Count it and split it.
$collection = $this->repository->getAll(); $collection = $this->repository->get();
$count = $collection->count(); $count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -145,11 +145,11 @@ class TriggerController extends Controller
// add a range: // add a range:
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]); $ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
} }
if (array_key_exists('accounts', $parameters) && '' !== $parameters['accounts']) { if (array_key_exists('accounts', $parameters) && is_array($parameters['accounts']) && count($parameters['accounts']) > 0) {
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]); $ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
} }
// file the rule(s) // fire the rule(s)
$ruleEngine->fire(); $ruleEngine->fire();
return response()->json([], 204); return response()->json([], 204);

View File

@@ -33,6 +33,7 @@ use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer; use FireflyIII\Transformers\CurrencyTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use JsonException;
use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -72,6 +73,7 @@ class ShowController extends Controller
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException * @throws FireflyException
* @throws JsonException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function index(): JsonResponse public function index(): JsonResponse
@@ -106,6 +108,8 @@ class ShowController extends Controller
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException
* @throws JsonException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function show(TransactionCurrency $currency): JsonResponse public function show(TransactionCurrency $currency): JsonResponse
@@ -130,6 +134,8 @@ class ShowController extends Controller
* Show a currency. * Show a currency.
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException
* @throws JsonException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function showDefault(): JsonResponse public function showDefault(): JsonResponse

View File

@@ -33,6 +33,7 @@ use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer; use FireflyIII\Transformers\CurrencyTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use JsonException;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
/** /**
@@ -74,6 +75,7 @@ class StoreController extends Controller
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException * @throws FireflyException
* @throws JsonException
*/ */
public function store(StoreRequest $request): JsonResponse public function store(StoreRequest $request): JsonResponse
{ {

View File

@@ -75,6 +75,8 @@ class UpdateController extends Controller
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException
* @throws JsonException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function disable(TransactionCurrency $currency): JsonResponse public function disable(TransactionCurrency $currency): JsonResponse
@@ -108,6 +110,8 @@ class UpdateController extends Controller
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
* *
* @return JsonResponse * @return JsonResponse
* @throws FireflyException
* @throws JsonException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function enable(TransactionCurrency $currency): JsonResponse public function enable(TransactionCurrency $currency): JsonResponse

View File

@@ -70,8 +70,8 @@ class AccountController extends Controller
{ {
Log::debug('Now in account search()'); Log::debug('Now in account search()');
$manager = $this->getManager(); $manager = $this->getManager();
$query = $request->get('query'); $query = trim((string) $request->get('query'));
$field = $request->get('field'); $field = trim((string) $request->get('field'));
$type = $request->get('type') ?? 'all'; $type = $request->get('type') ?? 'all';
if ('' === $query || !in_array($field, $this->validFields, true)) { if ('' === $query || !in_array($field, $this->validFields, true)) {
return response(null, 422); return response(null, 422);

View File

@@ -113,7 +113,7 @@ class BasicController extends Controller
// give new keys // give new keys
$return = []; $return = [];
foreach ($total as $entry) { foreach ($total as $entry) {
if (null === $code || (null !== $code && $code === $entry['currency_code'])) { if (null === $code || ($code === $entry['currency_code'])) {
$return[$entry['key']] = $entry; $return[$entry['key']] = $entry;
} }
} }
@@ -150,7 +150,9 @@ class BasicController extends Controller
foreach ($set as $transactionJournal) { foreach ($set as $transactionJournal) {
$currencyId = (int) $transactionJournal['currency_id']; $currencyId = (int) $transactionJournal['currency_id'];
$incomes[$currencyId] = $incomes[$currencyId] ?? '0'; $incomes[$currencyId] = $incomes[$currencyId] ?? '0';
$incomes[$currencyId] = bcadd($incomes[$currencyId], bcmul($transactionJournal['amount'], '-1')); $incomes[$currencyId] = bcadd($incomes[$currencyId],
bcmul($transactionJournal['amount'], '-1')
);
$sums[$currencyId] = $sums[$currencyId] ?? '0'; $sums[$currencyId] = $sums[$currencyId] ?? '0';
$sums[$currencyId] = bcadd($sums[$currencyId], bcmul($transactionJournal['amount'], '-1')); $sums[$currencyId] = bcadd($sums[$currencyId], bcmul($transactionJournal['amount'], '-1'));
} }
@@ -362,7 +364,7 @@ class BasicController extends Controller
function (Account $account) { function (Account $account) {
$includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth'); $includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
return null === $includeNetWorth ? true : '1' === $includeNetWorth; return null === $includeNetWorth || '1' === $includeNetWorth;
} }
); );

View File

@@ -30,6 +30,8 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Binder\EitherConfigKey; use FireflyIII\Support\Binder\EitherConfigKey;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Log; use Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/** /**
* Class ConfigurationController * Class ConfigurationController
@@ -94,6 +96,8 @@ class ConfigurationController extends Controller
* *
* @return array * @return array
* @throws FireflyException * @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
private function getDynamicConfiguration(): array private function getDynamicConfiguration(): array
{ {

View File

@@ -81,7 +81,7 @@ class UserController extends Controller
return response()->json([], 500); return response()->json([], 500);
} }
if ($admin->id !== $user->id && $this->repository->hasRole($admin, 'owner')) { if ($this->repository->hasRole($admin, 'owner')) {
$this->repository->destroy($user); $this->repository->destroy($user);
return response()->json([], 204); return response()->json([], 204);

View File

@@ -74,10 +74,24 @@ class MoveTransactionsRequest extends FormRequest
// validate start before end only if both are there. // validate start before end only if both are there.
$data = $validator->getData(); $data = $validator->getData();
if (array_key_exists('original_account', $data) && array_key_exists('destination_account', $data)) { if (array_key_exists('original_account', $data) && array_key_exists('destination_account', $data)) {
$this->validateMove($validator);
}
}
);
}
/**
* @param Validator $validator
* @return void
*/
private function validateMove(Validator $validator): void {
$data = $validator->getData();
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user()); $repository->setUser(auth()->user());
$original = $repository->find((int) $data['original_account']); $original = $repository->find((int) $data['original_account']);
$destination = $repository->find((int) $data['destination_account']); $destination = $repository->find((int) $data['destination_account']);
// not the same type:
if ($original->accountType->type !== $destination->accountType->type) { if ($original->accountType->type !== $destination->accountType->type) {
$validator->errors()->add('title', (string) trans('validation.same_account_type')); $validator->errors()->add('title', (string) trans('validation.same_account_type'));
@@ -86,6 +100,8 @@ class MoveTransactionsRequest extends FormRequest
// get currency pref: // get currency pref:
$originalCurrency = $repository->getAccountCurrency($original); $originalCurrency = $repository->getAccountCurrency($original);
$destinationCurrency = $repository->getAccountCurrency($destination); $destinationCurrency = $repository->getAccountCurrency($destination);
// check different scenario's.
if (null === $originalCurrency xor null === $destinationCurrency) { if (null === $originalCurrency xor null === $destinationCurrency) {
$validator->errors()->add('title', (string) trans('validation.same_account_currency')); $validator->errors()->add('title', (string) trans('validation.same_account_currency'));
@@ -100,6 +116,3 @@ class MoveTransactionsRequest extends FormRequest
} }
} }
} }
);
}
}

View File

@@ -128,7 +128,7 @@ class GenericRequest extends FormRequest
foreach ($array as $billId) { foreach ($array as $billId) {
$billId = (int) $billId; $billId = (int) $billId;
$bill = $repository->find($billId); $bill = $repository->find($billId);
if (null !== $billId) { if (null !== $bill) {
$this->bills->push($bill); $this->bills->push($bill);
} }
} }
@@ -160,7 +160,7 @@ class GenericRequest extends FormRequest
foreach ($array as $budgetId) { foreach ($array as $budgetId) {
$budgetId = (int) $budgetId; $budgetId = (int) $budgetId;
$budget = $repository->find($budgetId); $budget = $repository->find($budgetId);
if (null !== $budgetId) { if (null !== $budget) {
$this->budgets->push($budget); $this->budgets->push($budget);
} }
} }
@@ -192,7 +192,7 @@ class GenericRequest extends FormRequest
foreach ($array as $categoryId) { foreach ($array as $categoryId) {
$categoryId = (int) $categoryId; $categoryId = (int) $categoryId;
$category = $repository->find($categoryId); $category = $repository->find($categoryId);
if (null !== $categoryId) { if (null !== $category) {
$this->categories->push($category); $this->categories->push($category);
} }
} }
@@ -282,7 +282,7 @@ class GenericRequest extends FormRequest
foreach ($array as $tagId) { foreach ($array as $tagId) {
$tagId = (int) $tagId; $tagId = (int) $tagId;
$tag = $repository->find($tagId); $tag = $repository->find($tagId);
if (null !== $tagId) { if (null !== $tag) {
$this->tags->push($tag); $this->tags->push($tag);
} }
} }

View File

@@ -116,15 +116,15 @@ class StoreRequest extends FormRequest
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'active' => [new IsBoolean], 'active' => [new IsBoolean],
'include_net_worth' => [new IsBoolean], 'include_net_worth' => [new IsBoolean],
'account_role' => sprintf('in:%s|required_if:type,asset', $accountRoles), 'account_role' => sprintf('nullable|in:%s|required_if:type,asset', $accountRoles),
'credit_card_type' => sprintf('in:%s|required_if:account_role,ccAsset', $ccPaymentTypes), 'credit_card_type' => sprintf('nullable|in:%s|required_if:account_role,ccAsset', $ccPaymentTypes),
'monthly_payment_date' => 'date' . '|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull', 'monthly_payment_date' => 'nullable|date|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull',
'liability_type' => 'required_if:type,liability|required_if:type,liabilities|in:loan,debt,mortgage', 'liability_type' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:loan,debt,mortgage',
'liability_amount' => 'required_with:liability_start_date|min:0|numeric', 'liability_amount' => 'required_with:liability_start_date|min:0|numeric',
'liability_start_date' => 'required_with:liability_amount|date', 'liability_start_date' => 'required_with:liability_amount|date',
'liability_direction' => 'required_if:type,liability|required_if:type,liabilities|in:credit,debit', 'liability_direction' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:credit,debit',
'interest' => 'between:0,100|numeric', 'interest' => 'between:0,100|numeric',
'interest_period' => sprintf('in:%s', join(',', config('firefly.interest_periods'))), 'interest_period' => sprintf('nullable|in:%s', join(',', config('firefly.interest_periods'))),
'notes' => 'min:0|max:65536', 'notes' => 'min:0|max:65536',
]; ];

View File

@@ -50,6 +50,7 @@ class StoreRequest extends FormRequest
'name' => ['name', 'string'], 'name' => ['name', 'string'],
'active' => ['active', 'boolean'], 'active' => ['active', 'boolean'],
'order' => ['active', 'integer'], 'order' => ['active', 'integer'],
'notes' => ['notes', 'string'],
// auto budget currency: // auto budget currency:
'currency_id' => ['auto_budget_currency_id', 'integer'], 'currency_id' => ['auto_budget_currency_id', 'integer'],
@@ -74,6 +75,7 @@ class StoreRequest extends FormRequest
'active' => [new IsBoolean], 'active' => [new IsBoolean],
'currency_id' => 'exists:transaction_currencies,id', 'currency_id' => 'exists:transaction_currencies,id',
'currency_code' => 'exists:transaction_currencies,code', 'currency_code' => 'exists:transaction_currencies,code',
'notes' => 'nullable|between:1,65536',
// auto budget info // auto budget info
'auto_budget_type' => 'in:reset,rollover,none', '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_amount' => 'numeric|min:0|max:1000000000|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover',

View File

@@ -51,6 +51,7 @@ class UpdateRequest extends FormRequest
'name' => ['name', 'string'], 'name' => ['name', 'string'],
'active' => ['active', 'boolean'], 'active' => ['active', 'boolean'],
'order' => ['order', 'integer'], 'order' => ['order', 'integer'],
'notes' => ['notes', 'string'],
'currency_id' => ['auto_budget_currency_id', 'integer'], 'currency_id' => ['auto_budget_currency_id', 'integer'],
'currency_code' => ['auto_budget_currency_code', 'string'], 'currency_code' => ['auto_budget_currency_code', 'string'],
'auto_budget_type' => ['auto_budget_type', 'string'], 'auto_budget_type' => ['auto_budget_type', 'string'],
@@ -82,6 +83,7 @@ class UpdateRequest extends FormRequest
return [ return [
'name' => sprintf('between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id), 'name' => sprintf('between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id),
'active' => [new IsBoolean], 'active' => [new IsBoolean],
'notes' => 'nullable|between:1,65536',
'auto_budget_type' => 'in:reset,rollover,none', 'auto_budget_type' => 'in:reset,rollover,none',
'auto_budget_currency_id' => 'exists:transaction_currencies,id', 'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_currency_code' => 'exists:transaction_currencies,code', 'auto_budget_currency_code' => 'exists:transaction_currencies,code',

View File

@@ -141,32 +141,34 @@ class StoreRequest extends FormRequest
'first_date' => 'required|date', 'first_date' => 'required|date',
'apply_rules' => [new IsBoolean], 'apply_rules' => [new IsBoolean],
'active' => [new IsBoolean], 'active' => [new IsBoolean],
'repeat_until' => 'date', 'repeat_until' => 'nullable|date',
'nr_of_repetitions' => 'numeric|between:1,31', 'nr_of_repetitions' => 'nullable|numeric|between:1,31',
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly', 'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10', 'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'numeric|between:0,31', 'repetitions.*.skip' => 'nullable|numeric|between:0,31',
'repetitions.*.weekend' => 'numeric|min:1|max:4', 'repetitions.*.weekend' => 'numeric|min:1|max:4',
'transactions.*.description' => 'required|between:1,255', 'transactions.*.description' => 'required|between:1,255',
'transactions.*.amount' => 'required|numeric|gt:0', 'transactions.*.amount' => 'required|numeric|gt:0',
'transactions.*.foreign_amount' => 'numeric|gt:0', 'transactions.*.foreign_amount' => 'nullable|numeric|gt:0',
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id', 'transactions.*.currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code', 'transactions.*.currency_code' => 'nullable|min:3|max:3|exists:transaction_currencies,code',
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id', 'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code', 'transactions.*.foreign_currency_code' => 'nullable|min:3|max:3|exists:transaction_currencies,code',
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser], 'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.source_name' => 'between:1,255|nullable', 'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser], 'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.destination_name' => 'between:1,255|nullable', 'transactions.*.destination_name' => 'between:1,255|nullable',
// new and updated fields: // new and updated fields:
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser], 'transactions.*.budget_id' => ['nullable', 'mustExist:budgets,id', new BelongsUser],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser], 'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser], 'transactions.*.category_id' => ['nullable', 'mustExist:categories,id', new BelongsUser],
'transactions.*.category_name' => 'between:1,255|nullable', 'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.piggy_bank_id' => ['numeric', 'mustExist:piggy_banks,id', new BelongsUser], 'transactions.*.piggy_bank_id' => ['nullable', 'numeric', 'mustExist:piggy_banks,id', new BelongsUser],
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser], 'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser],
'transactions.*.tags' => 'between:1,64000', 'transactions.*.tags' => 'nullable|between:1,64000',
]; ];
} }

View File

@@ -155,33 +155,34 @@ class UpdateRequest extends FormRequest
'first_date' => 'date', 'first_date' => 'date',
'apply_rules' => [new IsBoolean], 'apply_rules' => [new IsBoolean],
'active' => [new IsBoolean], 'active' => [new IsBoolean],
'repeat_until' => 'date', 'repeat_until' => 'nullable|date',
'nr_of_repetitions' => 'numeric|between:1,31', 'nr_of_repetitions' => 'nullable|numeric|between:1,31',
'repetitions.*.type' => 'in:daily,weekly,ndom,monthly,yearly', 'repetitions.*.type' => 'in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10', 'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'numeric|between:0,31', 'repetitions.*.skip' => 'nullable|numeric|between:0,31',
'repetitions.*.weekend' => 'numeric|min:1|max:4', 'repetitions.*.weekend' => 'nullable|numeric|min:1|max:4',
'transactions.*.description' => 'between:1,255', 'transactions.*.description' => 'between:1,255',
'transactions.*.amount' => 'numeric|gt:0', 'transactions.*.amount' => 'numeric|gt:0',
'transactions.*.foreign_amount' => 'numeric|gt:0', 'transactions.*.foreign_amount' => 'nullable|numeric|gt:0',
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id', 'transactions.*.currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code', 'transactions.*.currency_code' => 'nullable|min:3|max:3|exists:transaction_currencies,code',
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id', 'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code', 'transactions.*.foreign_currency_code' => 'nullable|min:3|max:3|exists:transaction_currencies,code',
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser], 'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.source_name' => 'between:1,255|nullable', 'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser], 'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.destination_name' => 'between:1,255|nullable', 'transactions.*.destination_name' => 'between:1,255|nullable',
// new and updated fields: // new and updated fields:
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser], 'transactions.*.budget_id' => ['nullable', 'mustExist:budgets,id', new BelongsUser],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser], 'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser], 'transactions.*.category_id' => ['nullable', 'mustExist:categories,id', new BelongsUser],
'transactions.*.category_name' => 'between:1,255|nullable', 'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.piggy_bank_id' => ['numeric', 'mustExist:piggy_banks,id', new BelongsUser], 'transactions.*.piggy_bank_id' => ['nullable', 'numeric', 'mustExist:piggy_banks,id', new BelongsUser],
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser], 'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser],
'transactions.*.tags' => 'between:1,64000', 'transactions.*.tags' => 'nullable|between:1,64000',
]; ];
} }

View File

@@ -153,12 +153,14 @@ class StoreRequest extends FormRequest
function (Validator $validator) { function (Validator $validator) {
$this->atLeastOneTrigger($validator); $this->atLeastOneTrigger($validator);
$this->atLeastOneAction($validator); $this->atLeastOneAction($validator);
$this->atLeastOneActiveTrigger($validator);
$this->atLeastOneActiveAction($validator);
} }
); );
} }
/** /**
* Adds an error to the validator when there are no repetitions in the array of data. * Adds an error to the validator when there are no triggers in the array of data.
* *
* @param Validator $validator * @param Validator $validator
*/ */
@@ -186,4 +188,62 @@ class StoreRequest extends FormRequest
$validator->errors()->add('title', (string) trans('validation.at_least_one_action')); $validator->errors()->add('title', (string) trans('validation.at_least_one_action'));
} }
} }
/**
* Adds an error to the validator when there are no ACTIVE triggers in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneActiveTrigger(Validator $validator): void
{
$data = $validator->getData();
$triggers = $data['triggers'] ?? [];
// need at least one trigger
if (!is_countable($triggers) || empty($triggers)) {
return;
}
$allInactive = true;
$inactiveIndex = 0;
foreach ($triggers as $index => $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('triggers.%d.active', $inactiveIndex), (string) trans('validation.at_least_one_active_trigger'));
}
}
/**
* 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) || empty($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'));
}
}
} }

View File

@@ -55,7 +55,7 @@ class TriggerRequest extends FormRequest
*/ */
private function getDate(string $field): ?Carbon private function getDate(string $field): ?Carbon
{ {
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field)); return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
} }
/** /**
@@ -63,7 +63,7 @@ class TriggerRequest extends FormRequest
*/ */
private function getAccounts(): array private function getAccounts(): array
{ {
return $this->get('accounts'); return $this->get('accounts') ?? [];
} }
/** /**

View File

@@ -167,7 +167,9 @@ class UpdateRequest extends FormRequest
$validator->after( $validator->after(
function (Validator $validator) { function (Validator $validator) {
$this->atLeastOneTrigger($validator); $this->atLeastOneTrigger($validator);
$this->atLeastOneValidTrigger($validator);
$this->atLeastOneAction($validator); $this->atLeastOneAction($validator);
$this->atLeastOneValidAction($validator);
} }
); );
} }
@@ -187,6 +189,35 @@ 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 atLeastOneValidTrigger(Validator $validator): void
{
$data = $validator->getData();
$triggers = $data['triggers'] ?? [];
$allInactive = true;
$inactiveIndex = 0;
// need at least one trigger
if (is_array($triggers) && empty($triggers)) {
return;
}
foreach ($triggers as $index => $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('triggers.%d.active', $inactiveIndex), (string) trans('validation.at_least_one_active_trigger'));
}
}
/** /**
* Adds an error to the validator when there are no repetitions in the array of data. * Adds an error to the validator when there are no repetitions in the array of data.
* *
@@ -201,4 +232,34 @@ class UpdateRequest extends FormRequest
$validator->errors()->add('title', (string) trans('validation.at_least_one_action')); $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.
*
* @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) && empty($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'));
}
}
} }

View File

@@ -98,17 +98,17 @@ class StoreRequest extends FormRequest
// source of transaction. If everything is null, assume cash account. // source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string) $object['source_id']), 'source_id' => $this->integerFromValue((string) $object['source_id']),
'source_name' => $this->clearString($object['source_name'], false), 'source_name' => $this->clearString((string) $object['source_name'], false),
'source_iban' => $this->clearString($object['source_iban'], false), 'source_iban' => $this->clearString((string) $object['source_iban'], false),
'source_number' => $this->clearString($object['source_number'], false), 'source_number' => $this->clearString((string) $object['source_number'], false),
'source_bic' => $this->clearString($object['source_bic'], false), 'source_bic' => $this->clearString((string) $object['source_bic'], false),
// destination of transaction. If everything is null, assume cash account. // destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string) $object['destination_id']), 'destination_id' => $this->integerFromValue((string) $object['destination_id']),
'destination_name' => $this->clearString($object['destination_name'], false), 'destination_name' => $this->clearString((string) $object['destination_name'], false),
'destination_iban' => $this->clearString($object['destination_iban'], false), 'destination_iban' => $this->clearString((string) $object['destination_iban'], false),
'destination_number' => $this->clearString($object['destination_number'], false), 'destination_number' => $this->clearString((string) $object['destination_number'], false),
'destination_bic' => $this->clearString($object['destination_bic'], false), 'destination_bic' => $this->clearString((string) $object['destination_bic'], false),
// budget info // budget info
'budget_id' => $this->integerFromValue((string) $object['budget_id']), 'budget_id' => $this->integerFromValue((string) $object['budget_id']),

View File

@@ -293,7 +293,7 @@ class UpdateRequest extends FormRequest
'transactions.*.order' => 'numeric|min:0', 'transactions.*.order' => 'numeric|min:0',
// group id: // group id:
'transactions.*.transaction_journal_id' => ['numeric', 'exists:transaction_journals,id', new BelongsUser], 'transactions.*.transaction_journal_id' => ['nullable', 'numeric', new BelongsUser],
// currency info // currency info

View File

@@ -28,6 +28,7 @@ use FireflyIII\Rules\IsBoolean;
use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
/** /**
* Class UserUpdateRequest * Class UserUpdateRequest
@@ -43,7 +44,7 @@ class UserUpdateRequest extends FormRequest
*/ */
public function authorize(): bool public function authorize(): bool
{ {
return auth()->check() && auth()->user()->hasRole('owner'); return auth()->check();
} }
/** /**
@@ -83,4 +84,25 @@ class UserUpdateRequest extends FormRequest
]; ];
} }
/**
* Configure the validator instance.
*
* @param Validator $validator
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$current = $this->route()->parameter('user');
$validator->after(
static function (Validator $validator) use ($current) {
$isAdmin = auth()->user()->hasRole('owner');
// not admin, and not own user?
if (auth()->check() && false === $isAdmin && $current?->id !== auth()->user()->id) {
$validator->errors()->add('email', (string) trans('validation.invalid_selection'));
}
}
);
}
} }

View File

@@ -57,7 +57,6 @@ class CorrectOpeningBalanceCurrencies extends Command
* Execute the console command. * Execute the console command.
* *
* @return int * @return int
* @throws JsonException
*/ */
public function handle(): int public function handle(): int
{ {
@@ -136,6 +135,8 @@ class CorrectOpeningBalanceCurrencies extends Command
* @param Account $account * @param Account $account
* *
* @return TransactionCurrency * @return TransactionCurrency
* @throws JsonException
* @throws \FireflyIII\Exceptions\FireflyException
*/ */
private function getCurrency(Account $account): TransactionCurrency private function getCurrency(Account $account): TransactionCurrency
{ {

View File

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

View File

@@ -68,6 +68,7 @@ class RenameMetaFields extends Command
'sepa-ep' => 'sepa_ep', 'sepa-ep' => 'sepa_ep',
'sepa-ci' => 'sepa_ci', 'sepa-ci' => 'sepa_ci',
'sepa-batch-id' => 'sepa_batch_id', 'sepa-batch-id' => 'sepa_batch_id',
'external_uri' => 'external_url',
]; ];
foreach ($changes as $original => $update) { foreach ($changes as $original => $update) {
$this->rename($original, $update); $this->rename($original, $update);

View File

@@ -109,6 +109,8 @@ class DecryptDatabase extends Command
* @param string $table * @param string $table
* *
* @return bool * @return bool
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isDecrypted(string $table): bool private function isDecrypted(string $table): bool
{ {

View File

@@ -27,7 +27,6 @@ use Crypt;
use FireflyIII\Models\Attachment; use FireflyIII\Models\Attachment;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Log; use Log;
use Storage; use Storage;
@@ -62,10 +61,9 @@ class ScanAttachments extends Command
/** @var Attachment $attachment */ /** @var Attachment $attachment */
foreach ($attachments as $attachment) { foreach ($attachments as $attachment) {
$fileName = $attachment->fileName(); $fileName = $attachment->fileName();
try {
$encryptedContent = $disk->get($fileName); $encryptedContent = $disk->get($fileName);
} catch (FileNotFoundException $e) { if (null === $encryptedContent) {
$this->error(sprintf('Could not find data for attachment #%d: %s', $attachment->id, $e->getMessage())); Log::error(sprintf('No content for attachment #%d under filename "%s"', $attachment->id, $fileName));
continue; continue;
} }
try { try {

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Console\Commands\Tools;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob; use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\BillWarningCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob; use FireflyIII\Support\Cronjobs\RecurringCronjob;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use InvalidArgumentException; use InvalidArgumentException;
@@ -90,6 +91,17 @@ class Cron extends Command
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
/*
* Fire bill warning cron job
*/
try {
$this->billWarningCronJob($force, $date);
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$this->error($e->getMessage());
}
$this->info('More feedback on the cron jobs can be found in the log files.'); $this->info('More feedback on the cron jobs can be found in the log files.');
return 0; return 0;
@@ -150,4 +162,32 @@ class Cron extends Command
} }
} }
/**
* @param bool $force
* @param Carbon|null $date
* @throws FireflyException
*/
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->error(sprintf('"Send bill warnings" cron fired: %s', $autoBudget->message));
}
if ($autoBudget->jobSucceeded) {
$this->error(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
}
}
} }

View File

@@ -109,6 +109,8 @@ class AccountCurrencies extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -72,6 +72,8 @@ class AppendBudgetLimitPeriods extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -86,6 +86,8 @@ class BackToJournals extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isMigrated(): bool private function isMigrated(): bool
{ {
@@ -97,6 +99,8 @@ class BackToJournals extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -99,6 +99,8 @@ class BudgetLimitCurrency extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -96,6 +96,8 @@ class CCLiabilities extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -77,6 +77,8 @@ class CreateGroupMemberships extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -108,6 +108,8 @@ class MigrateAttachments extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -106,6 +106,8 @@ class MigrateJournalNotes extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -84,6 +84,8 @@ class MigrateRecurrenceMeta extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -77,6 +77,8 @@ class MigrateRecurrenceType extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -75,6 +75,8 @@ class MigrateTagLocations extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -129,6 +129,8 @@ class MigrateToGroups extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isMigrated(): bool private function isMigrated(): bool
{ {

View File

@@ -120,6 +120,8 @@ class MigrateToRules extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -115,6 +115,8 @@ class OtherCurrenciesCorrections extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -99,6 +99,8 @@ class RenameAccountMeta extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -123,6 +123,8 @@ class TransactionIdentifier extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -68,6 +68,9 @@ class TransferCurrenciesCorrections extends Command
* Execute the console command. * Execute the console command.
* *
* @return int * @return int
* @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function handle(): int public function handle(): int
{ {
@@ -134,6 +137,8 @@ class TransferCurrenciesCorrections extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -81,6 +81,8 @@ class UpgradeLiabilities extends Command
/** /**
* @return bool * @return bool
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
private function isExecuted(): bool private function isExecuted(): bool
{ {

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands; namespace FireflyIII\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Log; use Log;
use Storage; use Storage;
@@ -51,7 +50,7 @@ class VerifySecurityAlerts extends Command
* Execute the console command. * Execute the console command.
* *
* @return int * @return int
* @throws FileNotFoundException * @throws \League\Flysystem\FilesystemException
*/ */
public function handle(): int public function handle(): int
{ {

View File

@@ -42,7 +42,6 @@ class Kernel extends ConsoleKernel
{ {
$this->load(__DIR__ . '/Commands'); $this->load(__DIR__ . '/Commands');
/** @noinspection PhpIncludeInspection */
require base_path('routes/console.php'); require base_path('routes/console.php');
} }

View File

@@ -30,6 +30,6 @@ namespace FireflyIII\Enums;
class ClauseType class ClauseType
{ {
public const TRANSACTION = 'transaction'; public const TRANSACTION = 'transaction';
public const WHERE = 'where';
public const UPDATE = 'update'; public const UPDATE = 'update';
public const WHERE = 'where';
} }

View File

@@ -37,21 +37,16 @@ class AdminRequestedTestMessage extends Event
{ {
use SerializesModels; use SerializesModels;
/** @var string The users IP address */ public User $user;
public $ipAddress;
/** @var User The user */
public $user;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @param User $user * @param User $user
* @param string $ipAddress
*/ */
public function __construct(User $user, string $ipAddress) public function __construct(User $user)
{ {
Log::debug(sprintf('Triggered AdminRequestedTestMessage for user #%d (%s) and IP %s!', $user->id, $user->email, $ipAddress)); Log::debug(sprintf('Triggered AdminRequestedTestMessage for user #%d (%s)', $user->id, $user->email));
$this->user = $user; $this->user = $user;
$this->ipAddress = $ipAddress;
} }
} }

View File

@@ -36,20 +36,14 @@ class RegisteredUser extends Event
{ {
use SerializesModels; use SerializesModels;
/** @var string The users IP address */ public User $user;
public $ipAddress;
/** @var User The user */
public $user;
/** /**
* Create a new event instance. This event is triggered when a new user registers. * Create a new event instance. This event is triggered when a new user registers.
*
* @param User $user * @param User $user
* @param string $ipAddress
*/ */
public function __construct(User $user, string $ipAddress) public function __construct(User $user)
{ {
$this->user = $user; $this->user = $user;
$this->ipAddress = $ipAddress;
} }
} }

View File

@@ -40,10 +40,8 @@ class RequestedReportOnJournals
{ {
use Dispatchable, InteractsWithSockets, SerializesModels; use Dispatchable, InteractsWithSockets, SerializesModels;
/** @var Collection The transaction groups to report on. */ public Collection $groups;
public $groups; public int $userId;
/** @var int The ID of the user. */
public $userId;
/** /**
* Create a new event instance. * Create a new event instance.

View File

@@ -36,14 +36,9 @@ class UserChangedEmail extends Event
{ {
use SerializesModels; use SerializesModels;
/** @var string The user's IP address */ public string $newEmail;
public $ipAddress; public string $oldEmail;
/** @var string The user's new email address */ public User $user;
public $newEmail;
/** @var string The user's old email address */
public $oldEmail;
/** @var User The user itself */
public $user;
/** /**
* UserChangedEmail constructor. * UserChangedEmail constructor.
@@ -51,12 +46,10 @@ class UserChangedEmail extends Event
* @param User $user * @param User $user
* @param string $newEmail * @param string $newEmail
* @param string $oldEmail * @param string $oldEmail
* @param string $ipAddress
*/ */
public function __construct(User $user, string $newEmail, string $oldEmail, string $ipAddress) public function __construct(User $user, string $newEmail, string $oldEmail)
{ {
$this->user = $user; $this->user = $user;
$this->ipAddress = $ipAddress;
$this->oldEmail = $oldEmail; $this->oldEmail = $oldEmail;
$this->newEmail = $newEmail; $this->newEmail = $newEmail;
} }

View File

@@ -1,6 +1,7 @@
<?php <?php
/** /**
* HelpController.php * DestroyedTransactionGroup.php
* Copyright (c) 2019 james@firefly-iii.org * Copyright (c) 2019 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
@@ -18,33 +19,36 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Http\Controllers; namespace FireflyIII\Events;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Bill;
use Illuminate\Http\JsonResponse; use Illuminate\Queue\SerializesModels;
/** /**
* Class HelpController. * Class WarnUserAboutBill.
*
* @codeCoverageIgnore
*/ */
class HelpController extends Controller class WarnUserAboutBill extends Event
{ {
use SerializesModels;
public Bill $bill;
public int $diff;
public string $field;
/** /**
* Show help for a route. * @param Bill $bill
* * @param string $field
* @param string $route * @param int $diff
*
* @return JsonResponse
* @throws FireflyException
*/ */
public function show(string $route): JsonResponse public function __construct(Bill $bill, string $field, int $diff)
{ {
/** @var string $language */ $this->bill = $bill;
$language = app('preferences')->get('language', config('firefly.default_language', 'en_US'))->data; $this->field = $field;
$html = $this->getHelpText($route, $language); $this->diff = $diff;
return response()->json(['html' => $html]);
} }
} }

View File

@@ -71,9 +71,11 @@ class GracefulNotFoundHandler extends ExceptionHandler
return parent::render($request, $e); return parent::render($request, $e);
case 'accounts.show': case 'accounts.show':
case 'accounts.edit':
case 'accounts.show.all': case 'accounts.show.all':
return $this->handleAccount($request, $e); return $this->handleAccount($request, $e);
case 'transactions.show': case 'transactions.show':
case 'transactions.edit':
return $this->handleGroup($request, $e); return $this->handleGroup($request, $e);
case 'attachments.show': case 'attachments.show':
case 'attachments.edit': case 'attachments.edit':
@@ -119,7 +121,6 @@ class GracefulNotFoundHandler extends ExceptionHandler
$request->session()->reflash(); $request->session()->reflash();
return redirect(route('rules.index')); return redirect(route('rules.index'));
case 'transactions.edit':
case 'transactions.mass.edit': case 'transactions.mass.edit':
case 'transactions.mass.delete': case 'transactions.mass.delete':
case 'transactions.bulk.edit': case 'transactions.bulk.edit':

View File

@@ -153,6 +153,12 @@ class Handler extends ExceptionHandler
$userData['id'] = auth()->user()->id; $userData['id'] = auth()->user()->id;
$userData['email'] = auth()->user()->email; $userData['email'] = auth()->user()->email;
} }
$headers = [];
if (request()->headers) {
$headers = request()->headers->all();
}
$data = [ $data = [
'class' => get_class($e), 'class' => get_class($e),
'errorMessage' => $e->getMessage(), 'errorMessage' => $e->getMessage(),
@@ -165,6 +171,8 @@ class Handler extends ExceptionHandler
'url' => request()->fullUrl(), 'url' => request()->fullUrl(),
'userAgent' => request()->userAgent(), 'userAgent' => request()->userAgent(),
'json' => request()->acceptsJson(), 'json' => request()->acceptsJson(),
'method' => request()->method(),
'headers' => $headers,
]; ];
// create job that will mail. // create job that will mail.

View File

@@ -74,6 +74,7 @@ class AccountFactory
* *
* @return Account * @return Account
* @throws FireflyException * @throws FireflyException
* @throws JsonException
*/ */
public function findOrCreate(string $accountName, string $accountType): Account public function findOrCreate(string $accountName, string $accountType): Account
{ {
@@ -182,6 +183,7 @@ class AccountFactory
* @param array $data * @param array $data
* *
* @return Account * @return Account
* @throws FireflyException
* @throws JsonException * @throws JsonException
*/ */
private function createAccount(AccountType $type, array $data): Account private function createAccount(AccountType $type, array $data): Account
@@ -361,7 +363,6 @@ class AccountFactory
* @param array $data * @param array $data
* *
* @throws FireflyException * @throws FireflyException
* @throws JsonException
*/ */
private function storeOrder(Account $account, array $data): void private function storeOrder(Account $account, array $data): void
{ {

View File

@@ -58,12 +58,10 @@ class AccountMetaFactory
} }
// if $data has field and $entry is not null, update $entry: // if $data has field and $entry is not null, update $entry:
if (null !== $entry) {
$entry->data = $value; $entry->data = $value;
$entry->save(); $entry->save();
Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $value, $account->id, $account->name)); Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $value, $account->id, $account->name));
} }
}
if ('' === $value && null !== $entry) { if ('' === $value && null !== $entry) {
try { try {
$entry->delete(); $entry->delete();

View File

@@ -46,6 +46,7 @@ class BillFactory
* *
* @return Bill|null * @return Bill|null
* @throws FireflyException * @throws FireflyException
* @throws \JsonException
*/ */
public function create(array $data): ?Bill public function create(array $data): ?Bill
{ {

View File

@@ -43,6 +43,15 @@ class TransactionCurrencyFactory
*/ */
public function create(array $data): TransactionCurrency public function create(array $data): TransactionCurrency
{ {
// if the code already exists (deleted)
// force delete it and then create the transaction:
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
if (1 === $count) {
$old = TransactionCurrency::withTrashed()->whereCode($data['code'])->first();
$old->forceDelete();
Log::warning(sprintf('Force deleted old currency with ID #%d and code "%s".', $old->id, $data['code']));
}
try { try {
/** @var TransactionCurrency $result */ /** @var TransactionCurrency $result */
$result = TransactionCurrency::create( $result = TransactionCurrency::create(

View File

@@ -57,6 +57,7 @@ class TransactionGroupFactory
* @return TransactionGroup * @return TransactionGroup
* @throws DuplicateTransactionException * @throws DuplicateTransactionException
* @throws FireflyException * @throws FireflyException
* @throws \JsonException
*/ */
public function create(array $data): TransactionGroup public function create(array $data): TransactionGroup
{ {

View File

@@ -417,6 +417,8 @@ class TransactionJournalFactory
* @param Account $account * @param Account $account
* *
* @return TransactionCurrency * @return TransactionCurrency
* @throws FireflyException
* @throws JsonException
*/ */
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{ {

View File

@@ -64,6 +64,16 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $result; return $result;
} }
/**
* Return the preferred period.
*
* @return string
*/
protected function preferredPeriod(): string
{
return 'day';
}
/** /**
* Set accounts. * Set accounts.
* *
@@ -155,14 +165,4 @@ class MonthReportGenerator implements ReportGeneratorInterface
{ {
return $this; return $this;
} }
/**
* Return the preferred period.
*
* @return string
*/
protected function preferredPeriod(): string
{
return 'day';
}
} }

View File

@@ -49,6 +49,8 @@ class MonthReportGenerator implements ReportGeneratorInterface
* Generates the report. * Generates the report.
* *
* @return string * @return string
* @throws FireflyException
* @throws JsonException
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function generate(): string public function generate(): string
@@ -90,6 +92,80 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $result; return $result;
} }
/**
* Get the audit report.
*
* @param Account $account
* @param Carbon $date
*
* @return array
* @throws FireflyException
* @throws JsonException
*/
#[ArrayShape(['journals' => "array", 'currency' => "mixed", 'exists' => "bool", 'end' => "string", 'endBalance' => "mixed", 'dayBefore' => "string",
'dayBeforeBalance' => "mixed"])] public function getAuditReport(Account $account, Carbon $date): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountRepository->setUser($account->user);
/** @var JournalRepositoryInterface $journalRepository */
$journalRepository = app(JournalRepositoryInterface::class);
$journalRepository->setUser($account->user);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($this->start, $this->end)->withAccountInformation()
->withBudgetInformation()->withCategoryInformation()->withBillInformation();
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
$dayBeforeBalance = app('steam')->balance($account, $date);
$startBalance = $dayBeforeBalance;
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($account->user);
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
foreach ($journals as $index => $journal) {
$journals[$index]['balance_before'] = $startBalance;
$transactionAmount = $journal['amount'];
// make sure amount is in the right "direction".
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['amount']);
}
if ($currency->id === $journal['foreign_currency_id']) {
$transactionAmount = $journal['foreign_amount'];
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['foreign_amount']);
}
}
$newBalance = bcadd($startBalance, $transactionAmount);
$journals[$index]['balance_after'] = $newBalance;
$startBalance = $newBalance;
// add meta dates for each journal.
$journals[$index]['interest_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'interest_date');
$journals[$index]['book_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'book_date');
$journals[$index]['process_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'process_date');
$journals[$index]['due_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'due_date');
$journals[$index]['payment_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'payment_date');
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
}
$locale = app('steam')->getLocale();
return [
'journals' => $journals,
'currency' => $currency,
'exists' => !empty($journals),
'end' => $this->end->isoFormat((string) trans('config.month_and_day_moment_js', [], $locale)),
'endBalance' => app('steam')->balance($account, $this->end),
'dayBefore' => $date->isoFormat((string) trans('config.month_and_day_moment_js', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];
}
/** /**
* Account collection setter. * Account collection setter.
* *
@@ -187,78 +263,4 @@ class MonthReportGenerator implements ReportGeneratorInterface
{ {
return $this; return $this;
} }
/**
* Get the audit report.
*
* @param Account $account
* @param Carbon $date
*
* @return array
* @throws FireflyException
* @throws JsonException
*/
#[ArrayShape(['journals' => "array", 'currency' => "mixed", 'exists' => "bool", 'end' => "string", 'endBalance' => "mixed", 'dayBefore' => "string",
'dayBeforeBalance' => "mixed"])] public function getAuditReport(Account $account, Carbon $date): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountRepository->setUser($account->user);
/** @var JournalRepositoryInterface $journalRepository */
$journalRepository = app(JournalRepositoryInterface::class);
$journalRepository->setUser($account->user);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($this->start, $this->end)->withAccountInformation()
->withBudgetInformation()->withCategoryInformation()->withBillInformation();
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
$dayBeforeBalance = app('steam')->balance($account, $date);
$startBalance = $dayBeforeBalance;
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($account->user);
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
foreach ($journals as $index => $journal) {
$journals[$index]['balance_before'] = $startBalance;
$transactionAmount = $journal['amount'];
// make sure amount is in the right "direction".
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['amount']);
}
if ($currency->id === $journal['foreign_currency_id']) {
$transactionAmount = $journal['foreign_amount'];
if ($account->id === $journal['destination_account_id']) {
$transactionAmount = app('steam')->positive($journal['foreign_amount']);
}
}
$newBalance = bcadd($startBalance, $transactionAmount);
$journals[$index]['balance_after'] = $newBalance;
$startBalance = $newBalance;
// add meta dates for each journal.
$journals[$index]['interest_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'interest_date');
$journals[$index]['book_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'book_date');
$journals[$index]['process_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'process_date');
$journals[$index]['due_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'due_date');
$journals[$index]['payment_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'payment_date');
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
}
$locale = app('steam')->getLocale();
return [
'journals' => $journals,
'currency' => $currency,
'exists' => !empty($journals),
'end' => $this->end->formatLocalized((string)trans('config.month_and_day', [], $locale)),
'endBalance' => app('steam')->balance($account, $this->end),
'dayBefore' => $date->formatLocalized((string)trans('config.month_and_day', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];
}
} }

View File

@@ -66,38 +66,6 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$this->run(); $this->run();
} }
/**
* @inheritDoc
*/
public function getVersion(): int
{
return $this->version;
}
/**
* @param Collection $objects
*/
public function setObjects(Collection $objects): void
{
$this->objects = $objects;
}
/**
* @param int $trigger
*/
public function setTrigger(int $trigger): void
{
$this->trigger = $trigger;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/** /**
* @return Collection * @return Collection
*/ */
@@ -134,6 +102,8 @@ class StandardMessageGenerator implements MessageGeneratorInterface
/** /**
* @param Webhook $webhook * @param Webhook $webhook
* @param Model $model * @param Model $model
* @throws FireflyException
* @throws \JsonException
*/ */
private function generateMessage(Webhook $webhook, Model $model): void private function generateMessage(Webhook $webhook, Model $model): void
{ {
@@ -197,6 +167,14 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$this->storeMessage($webhook, $basicMessage); $this->storeMessage($webhook, $basicMessage);
} }
/**
* @inheritDoc
*/
public function getVersion(): int
{
return $this->version;
}
/** /**
* @param TransactionGroup $transactionGroup * @param TransactionGroup $transactionGroup
* *
@@ -220,9 +198,9 @@ class StandardMessageGenerator implements MessageGeneratorInterface
* @param Webhook $webhook * @param Webhook $webhook
* @param array $message * @param array $message
* *
* @return WebhookMessage * @return void
*/ */
private function storeMessage(Webhook $webhook, array $message): WebhookMessage private function storeMessage(Webhook $webhook, array $message): void
{ {
$webhookMessage = new WebhookMessage; $webhookMessage = new WebhookMessage;
$webhookMessage->webhook()->associate($webhook); $webhookMessage->webhook()->associate($webhook);
@@ -233,6 +211,29 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$webhookMessage->save(); $webhookMessage->save();
Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id)); Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id));
return $webhookMessage; }
/**
* @param Collection $objects
*/
public function setObjects(Collection $objects): void
{
$this->objects = $objects;
}
/**
* @param int $trigger
*/
public function setTrigger(int $trigger): void
{
$this->trigger = $trigger;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
} }
} }

View File

@@ -30,7 +30,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use Laravel\Passport\Events\AccessTokenCreated; use Laravel\Passport\Events\AccessTokenCreated;
use Log; use Log;
use Mail; use Mail;
use Request;
use Session; use Session;
/** /**
@@ -59,18 +58,16 @@ class APIEventHandler
$email = config('firefly.site_owner'); $email = config('firefly.site_owner');
} }
$ipAddress = Request::ip();
// see if user has alternative email address: // see if user has alternative email address:
$pref = app('preferences')->getForUser($user, 'remote_guard_alt_email'); $pref = app('preferences')->getForUser($user, 'remote_guard_alt_email');
if (null !== $pref) { if (null !== $pref) {
$email = (string) (is_array($pref->data) ? $email : $pref->data); $email = (string) (is_array($pref->data) ? $email : $pref->data);
} }
Log::debug(sprintf('Now in APIEventHandler::accessTokenCreated. Email is %s, IP is %s', $email, $ipAddress)); Log::debug(sprintf('Now in APIEventHandler::accessTokenCreated. Email is %s', $email));
try { try {
Log::debug('Trying to send message...'); Log::debug('Trying to send message...');
Mail::to($email)->send(new AccessTokenCreatedMail($email, $ipAddress)); Mail::to($email)->send(new AccessTokenCreatedMail);
} catch (Exception $e) { // @phpstan-ignore-line } catch (Exception $e) { // @phpstan-ignore-line
Log::debug('Send message failed! :('); Log::debug('Send message failed! :(');

View File

@@ -52,7 +52,6 @@ class AdminEventHandler
// is user even admin? // is user even admin?
if ($repository->hasRole($event->user, 'owner')) { if ($repository->hasRole($event->user, 'owner')) {
$email = $event->user->email; $email = $event->user->email;
$ipAddress = $event->ipAddress;
// if user is demo user, send to owner: // if user is demo user, send to owner:
if ($event->user->hasRole('demo')) { if ($event->user->hasRole('demo')) {
@@ -65,10 +64,10 @@ class AdminEventHandler
$email = $pref->data; $email = $pref->data;
} }
Log::debug(sprintf('Now in sendTestMessage event handler. Email is %s, IP is %s', $email, $ipAddress)); Log::debug(sprintf('Now in sendTestMessage event handler. Email is %s', $email));
try { try {
Log::debug('Trying to send message...'); Log::debug('Trying to send message...');
Mail::to($email)->send(new AdminTestMail($email, $ipAddress)); Mail::to($email)->send(new AdminTestMail($email));
// Laravel cannot pretend this process failed during testing. // Laravel cannot pretend this process failed during testing.
} catch (Exception $e) { // @phpstan-ignore-line } catch (Exception $e) { // @phpstan-ignore-line

View File

@@ -43,7 +43,6 @@ class AutomationHandler
* @param RequestedReportOnJournals $event * @param RequestedReportOnJournals $event
* *
* @return bool * @return bool
* @throws FireflyException
*/ */
public function reportJournals(RequestedReportOnJournals $event): bool public function reportJournals(RequestedReportOnJournals $event): bool
{ {
@@ -58,23 +57,9 @@ class AutomationHandler
$repository = app(UserRepositoryInterface::class); $repository = app(UserRepositoryInterface::class);
$user = $repository->find($event->userId); $user = $repository->find($event->userId);
if (null !== $user && 0 !== $event->groups->count()) { if (null !== $user && 0 !== $event->groups->count()) {
$email = $user->email;
// see if user has alternative email address:
$pref = app('preferences')->getForUser($user, 'remote_guard_alt_email');
if (null !== $pref) {
$email = $pref->data;
}
// if user is demo user, send to owner:
if ($user->hasRole('demo')) {
$email = config('firefly.site_owner');
}
try { try {
Log::debug('Trying to mail...'); Log::debug('Trying to mail...');
Mail::to($user->email)->send(new ReportNewJournalsMail($email, '127.0.0.1', $event->groups)); Mail::to($user->email)->send(new ReportNewJournalsMail($event->groups));
} catch (Exception $e) { // @phpstan-ignore-line } catch (Exception $e) { // @phpstan-ignore-line
Log::debug('Send message failed! :('); Log::debug('Send message failed! :(');

View File

@@ -0,0 +1,64 @@
<?php
/*
* BillEventHandler.php
* Copyright (c) 2022 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\WarnUserAboutBill;
use FireflyIII\Mail\BillWarningMail;
use Log;
use Mail;
/**
* Class BillEventHandler
*/
class BillEventHandler
{
/**
* @param WarnUserAboutBill $event
* @return void
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function warnAboutBill(WarnUserAboutBill $event): void
{
$bill = $event->bill;
$field = $event->field;
$diff = $event->diff;
$user = $bill->user;
$address = $user->email;
$ipAddress = request()?->ip();
// see if user has alternative email address:
$pref = app('preferences')->getForUser($user, 'remote_guard_alt_email');
if (null !== $pref) {
$address = $pref->data;
}
// send message:
Mail::to($address)->send(new BillWarningMail($bill, $field, $diff, $ipAddress));
Log::debug('warnAboutBill');
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* LDAPEventHandler.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Handlers\Events;
use FireflyIII\User;
use LdapRecord\Laravel\Events\Import\Imported;
use Log;
/**
* Class LDAPEventHandler
*/
class LDAPEventHandler
{
/**
* @param Imported $event
*/
public function importedUser(Imported $event)
{
Log::debug(sprintf('Now in %s', __METHOD__));
/** @var User $user */
$user = $event->eloquent;
$alternative = User::where('email', $user->email)->where('id', '!=', $user->id)->first();
if (null !== $alternative) {
Log::debug(sprintf('User #%d is created but user #%d already exists.', $user->id, $alternative->id));
$alternative->objectguid = $user->objectguid;
$alternative->domain = $user->domain;
$alternative->save();
$user->delete();
auth()->logout();
}
}
}

View File

@@ -229,11 +229,10 @@ class UserEventHandler
$newEmail = $event->newEmail; $newEmail = $event->newEmail;
$oldEmail = $event->oldEmail; $oldEmail = $event->oldEmail;
$user = $event->user; $user = $event->user;
$ipAddress = $event->ipAddress;
$token = app('preferences')->getForUser($user, 'email_change_confirm_token', 'invalid'); $token = app('preferences')->getForUser($user, 'email_change_confirm_token', 'invalid');
$uri = route('profile.confirm-email-change', [$token->data]); $uri = route('profile.confirm-email-change', [$token->data]);
try { try {
Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress)); Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $uri));
} catch (Exception $e) { // @phpstan-ignore-line } catch (Exception $e) { // @phpstan-ignore-line
Log::error($e->getMessage()); Log::error($e->getMessage());
@@ -255,12 +254,11 @@ class UserEventHandler
$newEmail = $event->newEmail; $newEmail = $event->newEmail;
$oldEmail = $event->oldEmail; $oldEmail = $event->oldEmail;
$user = $event->user; $user = $event->user;
$ipAddress = $event->ipAddress;
$token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid'); $token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid');
$hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $oldEmail)); $hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $oldEmail));
$uri = route('profile.undo-email-change', [$token->data, $hashed]); $uri = route('profile.undo-email-change', [$token->data, $hashed]);
try { try {
Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress)); Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $uri));
} catch (Exception $e) { // @phpstan-ignore-line } catch (Exception $e) { // @phpstan-ignore-line
Log::error($e->getMessage()); Log::error($e->getMessage());
@@ -311,7 +309,6 @@ class UserEventHandler
// get the email address // get the email address
$email = $event->user->email; $email = $event->user->email;
$uri = route('index'); $uri = route('index');
$ipAddress = $event->ipAddress;
// see if user has alternative email address: // see if user has alternative email address:
$pref = app('preferences')->getForUser($event->user, 'remote_guard_alt_email'); $pref = app('preferences')->getForUser($event->user, 'remote_guard_alt_email');
@@ -321,7 +318,7 @@ class UserEventHandler
// send email. // send email.
try { try {
Mail::to($email)->send(new RegisteredUserMail($uri, $ipAddress)); Mail::to($email)->send(new RegisteredUserMail($uri));
} catch (Exception $e) { // @phpstan-ignore-line } catch (Exception $e) { // @phpstan-ignore-line
Log::error($e->getMessage()); Log::error($e->getMessage());
@@ -334,11 +331,11 @@ class UserEventHandler
/** /**
* @param ActuallyLoggedIn $event * @param ActuallyLoggedIn $event
* @throws FireflyException
*/ */
public function storeUserIPAddress(ActuallyLoggedIn $event): void public function storeUserIPAddress(ActuallyLoggedIn $event): void
{ {
Log::debug('Now in storeUserIPAddress'); Log::debug('Now in storeUserIPAddress');
/** @var User $user */
$user = $event->user; $user = $event->user;
/** @var array $preference */ /** @var array $preference */
try { try {

View File

@@ -44,6 +44,8 @@ class VersionCheckEventHandler
* @param RequestedVersionCheckStatus $event * @param RequestedVersionCheckStatus $event
* *
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function checkForUpdates(RequestedVersionCheckStatus $event): void public function checkForUpdates(RequestedVersionCheckStatus $event): void
{ {
@@ -90,6 +92,8 @@ class VersionCheckEventHandler
* @param RequestedVersionCheckStatus $event * @param RequestedVersionCheckStatus $event
* *
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
protected function warnToCheckForUpdates(RequestedVersionCheckStatus $event): void protected function warnToCheckForUpdates(RequestedVersionCheckStatus $event): void
{ {

View File

@@ -28,7 +28,6 @@ use FireflyIII\Models\Attachment;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\EncryptException; use Illuminate\Contracts\Encryption\EncryptException;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Contracts\Filesystem\Filesystem; use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -77,15 +76,10 @@ class AttachmentHelper implements AttachmentHelperInterface
*/ */
public function getAttachmentContent(Attachment $attachment): string public function getAttachmentContent(Attachment $attachment): string
{ {
$encryptedData = ''; $encryptedData = (string) $this->uploadDisk->get(sprintf('at-%d.data', $attachment->id));
try {
$encryptedData = $this->uploadDisk->get(sprintf('at-%d.data', $attachment->id));
} catch (FileNotFoundException $e) {
Log::error($e->getMessage());
}
try { try {
$unencryptedData = Crypt::decrypt($encryptedData); // verified $unencryptedData = Crypt::decrypt($encryptedData); // verified
} catch (DecryptException | FileNotFoundException $e) { } catch (DecryptException $e) {
Log::error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage())); Log::error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage()));
$unencryptedData = $encryptedData; $unencryptedData = $encryptedData;
} }

View File

@@ -86,4 +86,61 @@ trait AmountCollection
return $this; return $this;
} }
/**
* Get transactions with a specific foreign amount.
*
* @param string $amount
*
* @return GroupCollectorInterface
*/
public function foreignAmountIs(string $amount): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($amount) {
$q->whereNotNull('source.foreign_amount');
$q->where('source.foreign_amount', app('steam')->negative($amount));
}
);
return $this;
}
/**
* Get transactions where the amount is less than.
*
* @param string $amount
*
* @return GroupCollectorInterface
*/
public function foreignAmountLess(string $amount): GroupCollectorInterface
{
$this->query->where(
function (EloquentBuilder $q) use ($amount) {
$q->whereNotNull('destination.foreign_amount');
$q->where('destination.foreign_amount', '<=', app('steam')->positive($amount));
}
);
return $this;
}
/**
* Get transactions where the amount is more than.
*
* @param string $amount
*
* @return GroupCollectorInterface
*/
public function foreignAmountMore(string $amount): GroupCollectorInterface
{
$this->query->where(
function (EloquentBuilder $q) use ($amount) {
$q->whereNotNull('destination.foreign_amount');
$q->where('destination.foreign_amount', '>=', app('steam')->positive($amount));
}
);
return $this;
}
} }

View File

@@ -0,0 +1,306 @@
<?php
/*
* AttachmentCollection.php
* Copyright (c) 2022 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collector\Extensions;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Log;
/**
* Trait AttachmentCollection
*/
trait AttachmentCollection
{
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameContains(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = str_contains(strtolower($attachment['filename']), strtolower($name)) || str_contains(strtolower($attachment['title']), strtolower($name));
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* Has attachments
*
* @return GroupCollectorInterface
*/
public function hasAttachments(): GroupCollectorInterface
{
Log::debug('Add filter on attachment ID.');
$this->joinAttachmentTables();
$this->query->whereNotNull('attachments.attachable_id');
return $this;
}
/**
* Join table to get attachment information.
*/
private function joinAttachmentTables(): void
{
if (false === $this->hasJoinedAttTables) {
// join some extra tables:
$this->hasJoinedAttTables = true;
$this->query->leftJoin('attachments', 'attachments.attachable_id', '=', 'transaction_journals.id')
->where(
static function (EloquentBuilder $q1) {
$q1->where('attachments.attachable_type', TransactionJournal::class);
//$q1->where('attachments.uploaded', true);
$q1->orWhereNull('attachments.attachable_type');
}
);
}
}
/**
* @inheritDoc
*/
public function withAttachmentInformation(): GroupCollectorInterface
{
$this->fields[] = 'attachments.id as attachment_id';
$this->fields[] = 'attachments.filename as attachment_filename';
$this->fields[] = 'attachments.title as attachment_title';
$this->fields[] = 'attachments.uploaded as attachment_uploaded';
$this->joinAttachmentTables();
return $this;
}
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameEnds(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = str_ends_with(strtolower($attachment['filename']), strtolower($name)) || str_ends_with(strtolower($attachment['title']), strtolower($name));
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameIs(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = $attachment['filename'] === $name || $attachment['title'] === $name;
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameStarts(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = str_starts_with(strtolower($attachment['filename']), strtolower($name)) || str_starts_with(strtolower($attachment['title']), strtolower($name));
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesAre(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && $notes === $value;
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesContains(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && str_contains(strtolower($notes), strtolower($value));
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesEnds(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && str_ends_with(strtolower($notes), strtolower($value));
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesStarts(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && str_starts_with(strtolower($notes), strtolower($value));
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* Has attachments
*
* @return GroupCollectorInterface
*/
public function hasNoAttachments(): GroupCollectorInterface
{
Log::debug('Add filter on no attachments.');
$this->joinAttachmentTables();
$this->query->whereNull('attachments.attachable_id');
return $this;
}
}

View File

@@ -32,33 +32,20 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
*/ */
trait CollectorProperties trait CollectorProperties
{ {
/** @var array The standard fields to select. */ private array $fields;
private $fields; private bool $hasAccountInfo;
/** @var bool Will be set to true if query result contains account information. (see function withAccountInformation). */ private bool $hasBillInformation;
private $hasAccountInfo; private bool $hasBudgetInformation;
/** @var bool Will be true if query result includes bill information. */ private bool $hasCatInformation;
private $hasBillInformation; private bool $hasJoinedAttTables;
/** @var bool Will be true if query result contains budget info. */
private $hasBudgetInformation;
/** @var bool Will be true if query result contains category info. */
private $hasCatInformation;
/** @var bool Will be true for attachments */
private $hasJoinedAttTables;
private bool $hasJoinedMetaTables; private bool $hasJoinedMetaTables;
/** @var bool Will be true of the query has the tag info tables joined. */ private bool $hasJoinedTagTables;
private $hasJoinedTagTables; private bool $hasNotesInformation;
/** @var bool */ private array $integerFields;
private $hasNotesInformation; private ?int $limit;
/** @var array */ private ?int $page;
private $integerFields; private array $postFilters;
/** @var int The maximum number of results. */ private HasMany $query;
private $limit; private int $total;
/** @var int The page to return. */ private ?User $user;
private $page;
/** @var HasMany The query object. */
private $query;
/** @var int Total number of results. */
private $total;
/** @var User The user object. */
private $user;
} }

View File

@@ -29,6 +29,7 @@ use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\Tag; use FireflyIII\Models\Tag;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -37,6 +38,101 @@ use Illuminate\Support\Collection;
*/ */
trait MetaCollection trait MetaCollection
{ {
/**
* @inheritDoc
*/
public function externalIdContains(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $externalId));
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinMetaDataTables(): void
{
if (false === $this->hasJoinedMetaTables) {
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
$this->fields[] = 'journal_meta.name as meta_name';
$this->fields[] = 'journal_meta.data as meta_data';
}
}
/**
* @inheritDoc
*/
public function externalIdEnds(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s"', $externalId));
return $this;
}
/**
* @inheritDoc
*/
public function externalIdStarts(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', 'LIKE', sprintf('"%s%%', $externalId));
return $this;
}
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlContains(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = str_replace('\\', '\\\\', trim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $url));
return $this;
}
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlEnds(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = str_replace('\\', '\\\\', ltrim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s', $url));
return $this;
}
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlStarts(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = str_replace('\\', '\\\\', rtrim($url, '"'));
//var_dump($url);
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%s%%', $url));
return $this;
}
/** /**
* Where has no tags. * Where has no tags.
@@ -51,6 +147,73 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @return GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface
{
$this->fields[] = 'tags.id as tag_id';
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinTagTables(): void
{
if (false === $this->hasJoinedTagTables) {
// join some extra tables:
$this->hasJoinedTagTables = true;
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
$this->query->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id');
}
}
/**
* @inheritDoc
*/
public function internalReferenceContains(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $externalId));
return $this;
}
/**
* @inheritDoc
*/
public function internalReferenceEnds(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s"', $externalId));
return $this;
}
/**
* @inheritDoc
*/
public function internalReferenceStarts(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'LIKE', sprintf('"%s%%', $externalId));
return $this;
}
/** /**
* @param string $value * @param string $value
* *
@@ -64,6 +227,29 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function withNotes(): GroupCollectorInterface
{
if (false === $this->hasNotesInformation) {
// join bill table
$this->query->leftJoin(
'notes',
static function (JoinClause $join) {
$join->on('notes.noteable_id', '=', 'transaction_journals.id');
$join->where('notes.noteable_type', '=', 'FireflyIII\Models\TransactionJournal');
$join->whereNull('notes.deleted_at');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
return $this;
}
/** /**
* @param string $value * @param string $value
* *
@@ -118,6 +304,25 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Will include bill name + ID, if any.
*
* @return GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface
{
if (false === $this->hasBillInformation) {
// join bill table
$this->query->leftJoin('bills', 'bills.id', '=', 'transaction_journals.bill_id');
// add fields
$this->fields[] = 'bills.id as bill_id';
$this->fields[] = 'bills.name as bill_name';
$this->hasBillInformation = true;
}
return $this;
}
/** /**
* Limit the search to a specific set of bills. * Limit the search to a specific set of bills.
* *
@@ -148,6 +353,27 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Will include budget ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface
{
if (false === $this->hasBudgetInformation) {
// join link table
$this->query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id');
// add fields
$this->fields[] = 'budgets.id as budget_id';
$this->fields[] = 'budgets.name as budget_name';
$this->hasBudgetInformation = true;
}
return $this;
}
/** /**
* Limit the search to a specific set of budgets. * Limit the search to a specific set of budgets.
* *
@@ -182,6 +408,27 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Will include category ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface
{
if (false === $this->hasCatInformation) {
// join link table
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id');
// add fields
$this->fields[] = 'categories.id as category_id';
$this->fields[] = 'categories.name as category_name';
$this->hasCatInformation = true;
}
return $this;
}
/** /**
* Limit the search to a specific category. * Limit the search to a specific category.
* *
@@ -202,10 +449,7 @@ trait MetaCollection
*/ */
public function setExternalId(string $externalId): GroupCollectorInterface public function setExternalId(string $externalId): GroupCollectorInterface
{ {
if (false === $this->hasJoinedMetaTables) { $this->joinMetaDataTables();
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
}
$this->query->where('journal_meta.name', '=', 'external_id'); $this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($externalId))); $this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($externalId)));
@@ -215,33 +459,11 @@ trait MetaCollection
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function withoutExternalUrl(): GroupCollectorInterface public function setExternalUrl(string $url): GroupCollectorInterface
{ {
if (false === $this->hasJoinedMetaTables) { $this->joinMetaDataTables();
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
}
$this->query->where(function(Builder $q1) {
$q1->where(function(Builder $q2) {
$q2->where('journal_meta.name', '=', 'external_url');
$q2->whereNull('journal_meta.data');
})->orWhereNull('journal_meta.name');
});
return $this;
}
/**
* @inheritDoc
*/
public function withExternalUrl(): GroupCollectorInterface
{
if (false === $this->hasJoinedMetaTables) {
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
}
$this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereNotNull('journal_meta.data'); $this->query->where('journal_meta.data', '=', json_encode($url));
return $this; return $this;
} }
@@ -251,10 +473,7 @@ trait MetaCollection
*/ */
public function setInternalReference(string $internalReference): GroupCollectorInterface public function setInternalReference(string $internalReference): GroupCollectorInterface
{ {
if (false === $this->hasJoinedMetaTables) { $this->joinMetaDataTables();
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
}
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $internalReference)); $this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $internalReference));
@@ -262,6 +481,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function setRecurrenceId(string $recurringId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'recurrence_id');
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($recurringId)));
return $this;
}
/** /**
* Limit results to a specific tag. * Limit results to a specific tag.
* *
@@ -292,6 +523,35 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Without tags
*
* @param Collection $tags
*
* @return GroupCollectorInterface
*/
public function setWithoutSpecificTags(Collection $tags): GroupCollectorInterface
{
$this->withTagInformation();
// this method adds a "postFilter" to the collector.
$list = $tags->pluck('tag')->toArray();
$filter = function (int $index, array $object) use ($list): bool {
foreach ($object['transactions'] as $transaction) {
foreach ($transaction['tags'] as $tag) {
if (in_array($tag['name'], $list)) {
return false;
}
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
@@ -304,7 +564,7 @@ trait MetaCollection
} }
/** /**
* Limit results to transactions without a bill.. * Limit results to transactions without a bill.
* *
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
@@ -316,25 +576,6 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Will include bill name + ID, if any.
*
* @return GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface
{
if (false === $this->hasBillInformation) {
// join bill table
$this->query->leftJoin('bills', 'bills.id', '=', 'transaction_journals.bill_id');
// add fields
$this->fields[] = 'bills.id as bill_id';
$this->fields[] = 'bills.name as bill_name';
$this->hasBillInformation = true;
}
return $this;
}
/** /**
* Limit results to a transactions without a budget.. * Limit results to a transactions without a budget..
* *
@@ -348,27 +589,6 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Will include budget ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface
{
if (false === $this->hasBudgetInformation) {
// join link table
$this->query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id');
// add fields
$this->fields[] = 'budgets.id as budget_id';
$this->fields[] = 'budgets.name as budget_name';
$this->hasBudgetInformation = true;
}
return $this;
}
/** /**
* Limit results to a transactions without a category. * Limit results to a transactions without a category.
* *
@@ -382,63 +602,14 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Will include category ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface
{
if (false === $this->hasCatInformation) {
// join link table
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id');
// add fields
$this->fields[] = 'categories.id as category_id';
$this->fields[] = 'categories.name as category_name';
$this->hasCatInformation = true;
}
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function withNotes(): GroupCollectorInterface public function withExternalUrl(): GroupCollectorInterface
{ {
if (false === $this->hasNotesInformation) { $this->joinMetaDataTables();
// join bill table $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->leftJoin( $this->query->whereNotNull('journal_meta.data');
'notes',
static function (JoinClause $join) {
$join->on('notes.noteable_id', '=', 'transaction_journals.id');
$join->where('notes.noteable_type', '=', 'FireflyIII\Models\TransactionJournal');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface
{
$this->fields[] = 'tags.id as tag_id';
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();
return $this; return $this;
} }
@@ -481,13 +652,37 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function withoutExternalUrl(): GroupCollectorInterface
{
$this->joinMetaDataTables();
// TODO not sure if this will work properly.
$this->query->where(function (Builder $q1) {
$q1->where(function (Builder $q2) {
$q2->where('journal_meta.name', '=', 'external_url');
$q2->whereNull('journal_meta.data');
})->orWhere(function (Builder $q3) {
$q3->where('journal_meta.name', '!=', 'external_url');
})->orWhere(function (Builder $q4) {
$q4->whereNull('journal_meta.name');
});
});
return $this;
}
/** /**
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function withoutNotes(): GroupCollectorInterface public function withoutNotes(): GroupCollectorInterface
{ {
$this->withNotes(); $this->withNotes();
$this->query->whereNull('notes.text'); $this->query->where(function (Builder $q) {
$q->whereNull('notes.text');
$q->orWhere('notes.text', '');
});
return $this; return $this;
} }
@@ -504,17 +699,4 @@ trait MetaCollection
return $this; return $this;
} }
/**
* Join table to get tag information.
*/
protected function joinTagTables(): void
{
if (false === $this->hasJoinedTagTables) {
// join some extra tables:
$this->hasJoinedTagTables = true;
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
$this->query->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id');
}
}
} }

View File

@@ -32,6 +32,383 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
*/ */
trait TimeCollection trait TimeCollection
{ {
/**
* @param string $day
* @return GroupCollectorInterface
*/
public function dayAfter(string $day): GroupCollectorInterface
{
$this->query->whereDay('transaction_journals.date', '>=', $day);
return $this;
}
/**
* @param string $day
* @return GroupCollectorInterface
*/
public function dayBefore(string $day): GroupCollectorInterface
{
$this->query->whereDay('transaction_journals.date', '<=', $day);
return $this;
}
/**
* @param string $day
* @return GroupCollectorInterface
*/
public function dayIs(string $day): GroupCollectorInterface
{
$this->query->whereDay('transaction_journals.date', '=', $day);
return $this;
}
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function metaDayAfter(string $day, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $day): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->day >= (int) $day;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @inheritDoc
*/
public function withMetaDate(string $field): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', $field);
$this->query->whereNotNull('journal_meta.data');
return $this;
}
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function metaDayBefore(string $day, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $day): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->day <= (int) $day;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function metaDayIs(string $day, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $day): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return (int) $day === $transaction[$field]->day;
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function metaMonthAfter(string $month, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $month): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->month >= (int) $month;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function metaMonthBefore(string $month, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $month): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->month <= (int) $month;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function metaMonthIs(string $month, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $month): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return (int) $month === $transaction[$field]->month;
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function metaYearAfter(string $year, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $year): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->year >= (int) $year;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function metaYearBefore(string $year, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $year): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->year <= (int) $year;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function metaYearIs(string $year, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $year): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $year === (string) $transaction[$field]->year;
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param string $month
* @return GroupCollectorInterface
*/
public function monthAfter(string $month): GroupCollectorInterface
{
$this->query->whereMonth('transaction_journals.date', '>=', $month);
return $this;
}
/**
* @param string $month
* @return GroupCollectorInterface
*/
public function monthBefore(string $month): GroupCollectorInterface
{
$this->query->whereMonth('transaction_journals.date', '<=', $month);
return $this;
}
/**
* @param string $month
* @return GroupCollectorInterface
*/
public function monthIs(string $month): GroupCollectorInterface
{
$this->query->whereMonth('transaction_journals.date', '=', $month);
return $this;
}
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function objectDayAfter(string $day, string $field): GroupCollectorInterface
{
$this->query->whereDay(sprintf('transaction_journals.%s', $field), '>=', $day);
return $this;
}
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function objectDayBefore(string $day, string $field): GroupCollectorInterface
{
$this->query->whereDay(sprintf('transaction_journals.%s', $field), '<=', $day);
return $this;
}
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function objectDayIs(string $day, string $field): GroupCollectorInterface
{
$this->query->whereDay(sprintf('transaction_journals.%s', $field), '=', $day);
return $this;
}
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function objectMonthAfter(string $month, string $field): GroupCollectorInterface
{
$this->query->whereMonth(sprintf('transaction_journals.%s', $field), '>=', $month);
return $this;
}
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function objectMonthBefore(string $month, string $field): GroupCollectorInterface
{
$this->query->whereMonth(sprintf('transaction_journals.%s', $field), '<=', $month);
return $this;
}
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function objectMonthIs(string $month, string $field): GroupCollectorInterface
{
$this->query->whereMonth(sprintf('transaction_journals.%s', $field), '=', $month);
return $this;
}
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function objectYearAfter(string $year, string $field): GroupCollectorInterface
{
$this->query->whereYear(sprintf('transaction_journals.%s', $field), '>=', $year);
return $this;
}
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function objectYearBefore(string $year, string $field): GroupCollectorInterface
{
$this->query->whereYear(sprintf('transaction_journals.%s', $field), '<=', $year);
return $this;
}
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function objectYearIs(string $year, string $field): GroupCollectorInterface
{
$this->query->whereYear(sprintf('transaction_journals.%s', $field), '=', $year);
return $this;
}
/** /**
* Collect transactions after a specific date. * Collect transactions after a specific date.
@@ -80,6 +457,123 @@ trait TimeCollection
return $this; return $this;
} }
/**
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setMetaAfter(Carbon $date, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$date->startOfDay();
$filter = function (int $index, array $object) use ($field, $date): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->gte($date);
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setMetaBefore(Carbon $date, string $field): GroupCollectorInterface
{
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $date): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->lte($date);
}
}
return true;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param string $field
* @return GroupCollectorInterface
*/
public function setMetaDateRange(Carbon $start, Carbon $end, string $field): GroupCollectorInterface
{
if ($end < $start) {
[$start, $end] = [$end, $start];
}
$end = clone $end; // this is so weird, but it works if $end and $start secretly point to the same object.
$end->endOfDay();
$start->startOfDay();
$this->withMetaDate($field);
$filter = function (int $index, array $object) use ($field, $start, $end): bool {
foreach ($object['transactions'] as $transaction) {
if (array_key_exists($field, $transaction) && $transaction[$field] instanceof Carbon
) {
return $transaction[$field]->gte($start) && $transaction[$field]->lte($end);
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/**
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setObjectAfter(Carbon $date, string $field): GroupCollectorInterface
{
$afterStr = $date->format('Y-m-d 00:00:00');
$this->query->where(sprintf('transaction_journals.%s', $field), '>=', $afterStr);
return $this;
}
/**
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setObjectBefore(Carbon $date, string $field): GroupCollectorInterface
{
die('a');
}
/**
* @param Carbon $start
* @param Carbon $end
* @param string $field
* @return GroupCollectorInterface
*/
public function setObjectRange(Carbon $start, Carbon $end, string $field): GroupCollectorInterface
{
$after = $start->format('Y-m-d 00:00:00');
$before = $end->format('Y-m-d 23:59:59');
$this->query->where(sprintf('transaction_journals.%s', $field), '>=', $after);
$this->query->where(sprintf('transaction_journals.%s', $field), '<=', $before);
return $this;
}
/** /**
* Set the start and end time of the results to return. * Set the start and end time of the results to return.
* *
@@ -120,22 +614,9 @@ trait TimeCollection
return $this; return $this;
} }
public function yearIs(string $year): GroupCollectorInterface public function yearAfter(string $year): GroupCollectorInterface
{ {
$this->query->whereYear('transaction_journals.date', '=', $year); $this->query->whereYear('transaction_journals.date', '>=', $year);
return $this;
}
public function monthIs(string $month): GroupCollectorInterface
{
$this->query->whereMonth('transaction_journals.date', '=', $month);
return $this;
}
public function dayIs(string $day): GroupCollectorInterface
{
$this->query->whereDay('transaction_journals.date', '=', $day);
return $this; return $this;
} }
@@ -145,35 +626,10 @@ trait TimeCollection
return $this; return $this;
} }
public function monthBefore(string $month): GroupCollectorInterface public function yearIs(string $year): GroupCollectorInterface
{ {
$this->query->whereMonth('transaction_journals.date', '<=', $month); $this->query->whereYear('transaction_journals.date', '=', $year);
return $this;
}
public function dayBefore(string $day): GroupCollectorInterface
{
$this->query->whereDay('transaction_journals.date', '<=', $day);
return $this; return $this;
} }
public function yearAfter(string $year): GroupCollectorInterface
{
$this->query->whereYear('transaction_journals.date', '>=', $year);
return $this;
}
public function monthAfter(string $month): GroupCollectorInterface
{
$this->query->whereMonth('transaction_journals.date', '>=', $month);
return $this;
}
public function dayAfter(string $day): GroupCollectorInterface
{
$this->query->whereDay('transaction_journals.date', '>=', $day);
return $this;
}
} }

View File

@@ -25,9 +25,11 @@ namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon; use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException; use Carbon\Exceptions\InvalidDateException;
use Closure;
use Exception; use Exception;
use FireflyIII\Helpers\Collector\Extensions\AccountCollection; use FireflyIII\Helpers\Collector\Extensions\AccountCollection;
use FireflyIII\Helpers\Collector\Extensions\AmountCollection; use FireflyIII\Helpers\Collector\Extensions\AmountCollection;
use FireflyIII\Helpers\Collector\Extensions\AttachmentCollection;
use FireflyIII\Helpers\Collector\Extensions\CollectorProperties; use FireflyIII\Helpers\Collector\Extensions\CollectorProperties;
use FireflyIII\Helpers\Collector\Extensions\MetaCollection; use FireflyIII\Helpers\Collector\Extensions\MetaCollection;
use FireflyIII\Helpers\Collector\Extensions\TimeCollection; use FireflyIII\Helpers\Collector\Extensions\TimeCollection;
@@ -48,13 +50,18 @@ use Log;
*/ */
class GroupCollector implements GroupCollectorInterface class GroupCollector implements GroupCollectorInterface
{ {
use CollectorProperties, AccountCollection, AmountCollection, TimeCollection, MetaCollection; use CollectorProperties, AccountCollection, AmountCollection, TimeCollection, MetaCollection, AttachmentCollection;
/** /**
* Group collector constructor. * Group collector constructor.
*/ */
public function __construct() public function __construct()
{ {
$this->postFilters = [];
$this->user = null;
$this->limit = null;
$this->page = null;
$this->hasAccountInfo = false; $this->hasAccountInfo = false;
$this->hasCatInformation = false; $this->hasCatInformation = false;
$this->hasBudgetInformation = false; $this->hasBudgetInformation = false;
@@ -198,6 +205,26 @@ class GroupCollector implements GroupCollectorInterface
return $this; return $this;
} }
/**
*
*/
public function dumpQuery(): void
{
echo $this->query->select($this->fields)->toSql();
echo '<pre>';
print_r($this->query->getBindings());
echo '</pre>';
}
/**
*
*/
public function dumpQueryInLogs(): void
{
Log::debug($this->query->select($this->fields)->toSql());
Log::debug('Bindings', $this->query->getBindings());
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -241,6 +268,11 @@ class GroupCollector implements GroupCollectorInterface
// now to parse this into an array. // now to parse this into an array.
$collection = $this->parseArray($result); $collection = $this->parseArray($result);
// filter the array using all available post filters:
$collection = $this->postFilterCollection($collection);
// count it and continue:
$this->total = $collection->count(); $this->total = $collection->count();
// now filter the array according to the page and the limit (if necessary) // now filter the array according to the page and the limit (if necessary)
@@ -253,6 +285,285 @@ class GroupCollector implements GroupCollectorInterface
return $collection; return $collection;
} }
/**
* @param Collection $collection
*
* @return Collection
*/
private function parseArray(Collection $collection): Collection
{
$groups = [];
/** @var TransactionJournal $augumentedJournal */
foreach ($collection as $augumentedJournal) {
$groupId = $augumentedJournal->transaction_group_id;
if (!array_key_exists($groupId, $groups)) {
// make new array
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
$groupArray = [
'id' => (int) $augumentedJournal->transaction_group_id,
'user_id' => (int) $augumentedJournal->user_id,
'title' => $augumentedJournal->transaction_group_title,
'transaction_type' => $parsedGroup['transaction_type_type'],
'count' => 1,
'sums' => [],
'transactions' => [],
];
$journalId = (int) $augumentedJournal->transaction_journal_id;
$groupArray['transactions'][$journalId] = $parsedGroup;
$groups[$groupId] = $groupArray;
continue;
}
// or parse the rest.
$journalId = (int) $augumentedJournal->transaction_journal_id;
if (array_key_exists($journalId, $groups[$groupId]['transactions'])) {
// append data to existing group + journal (for multiple tags or multiple attachments)
$groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
$groups[$groupId]['transactions'][$journalId] = $this->mergeAttachments($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
}
if (!array_key_exists($journalId, $groups[$groupId]['transactions'])) {
// create second, third, fourth split:
$groups[$groupId]['count']++;
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal);
}
}
$groups = $this->parseSums($groups);
return new Collection($groups);
}
/**
* @param TransactionJournal $augumentedJournal
*
* @return array
*/
private function parseAugmentedJournal(TransactionJournal $augumentedJournal): array
{
$result = $augumentedJournal->toArray();
$result['tags'] = [];
$result['attachments'] = [];
$result['interest_date'] = null;
$result['payment_date'] = null;
$result['invoice_date'] = null;
$result['book_date'] = null;
$result['due_date'] = null;
$result['process_date'] = null;
try {
$result['date'] = new Carbon($result['date'], 'UTC');
$result['created_at'] = new Carbon($result['created_at'], 'UTC');
$result['updated_at'] = new Carbon($result['updated_at'], 'UTC');
// this is going to happen a lot:
$result['date']->setTimezone(config('app.timezone'));
$result['created_at']->setTimezone(config('app.timezone'));
$result['updated_at']->setTimezone(config('app.timezone'));
} catch (Exception $e) { // @phpstan-ignore-line
Log::error($e->getMessage());
}
// try to process meta date value (if present)
$dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date'];
if (array_key_exists('meta_name', $result) && in_array($result['meta_name'], $dates, true)) {
$name = $result['meta_name'];
if (array_key_exists('meta_data', $result) && '' !== (string) $result['meta_data']) {
$result[$name] = Carbon::createFromFormat('!Y-m-d', substr(json_decode($result['meta_data']), 0, 10));
}
}
// convert values to integers:
$result = $this->convertToInteger($result);
$result['reconciled'] = 1 === (int) $result['reconciled'];
if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well.
$tagId = (int) $augumentedJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($augumentedJournal['tag_date']);
} catch (InvalidDateException $e) {
Log::debug(sprintf('Could not parse date: %s', $e->getMessage()));
}
$result['tags'][$tagId] = [
'id' => (int) $result['tag_id'],
'name' => $result['tag_name'],
'date' => $tagDate,
'description' => $result['tag_description'],
];
}
// also merge attachments:
if (array_key_exists('attachment_id', $result)) {
$uploaded = 1 === (int) $result['attachment_uploaded'];
$attachmentId = (int) $augumentedJournal['attachment_id'];
if (0 !== $attachmentId && $uploaded) {
$result['attachments'][$attachmentId] = [
'id' => $attachmentId,
'filename' => $augumentedJournal['attachment_filename'],
'title' => $augumentedJournal['attachment_title'],
];
}
}
// unset various fields:
unset($result['tag_id'], $result['meta_data'], $result['meta_name'],
$result['tag_name'], $result['tag_date'], $result['tag_description'],
$result['tag_latitude'], $result['tag_longitude'], $result['tag_zoom_level'],
$result['attachment_filename'], $result['attachment_id']
);
return $result;
}
/**
* Convert a selected set of fields to arrays.
*
* @param array $array
*
* @return array
*/
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int) $array[$field] : null;
}
return $array;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeTags(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int) $newJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($newArray['tag_date']);
} catch (InvalidDateException $e) {
Log::debug(sprintf('Could not parse date: %s', $e->getMessage()));
}
$existingJournal['tags'][$tagId] = [
'id' => (int) $newArray['tag_id'],
'name' => $newArray['tag_name'],
'date' => $tagDate,
'description' => $newArray['tag_description'],
];
}
return $existingJournal;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeAttachments(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int) $newJournal['attachment_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
];
}
return $existingJournal;
}
/**
* @param array $groups
*
* @return array
*/
private function parseSums(array $groups): array
{
/**
* @var int $groudId
* @var array $group
*/
foreach ($groups as $groudId => $group) {
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
$currencyId = (int) $transaction['currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
$groups[$groudId]['sums'][$currencyId]['currency_id'] = $currencyId;
$groups[$groudId]['sums'][$currencyId]['currency_code'] = $transaction['currency_code'];
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount'] ?? '0');
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int) $transaction['foreign_currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
$groups[$groudId]['sums'][$currencyId]['currency_id'] = $currencyId;
$groups[$groudId]['sums'][$currencyId]['currency_code'] = $transaction['foreign_currency_code'];
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['foreign_currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['foreign_currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd(
$groups[$groudId]['sums'][$currencyId]['amount'],
$transaction['foreign_amount'] ?? '0'
);
}
}
}
return $groups;
}
/**
* @param Collection $collection
* @return Collection
*/
private function postFilterCollection(Collection $collection): Collection
{
$currentCollection = $collection;
/**
* @var int $i
* @var Closure $function
*/
foreach ($this->postFilters as $function) {
$nextCollection = new Collection;
// loop everything in the current collection
// and save it (or not) in the new collection.
// that new collection is the next current collection
/**
* @var int $index
* @var array $item
*/
foreach ($currentCollection as $ii => $item) {
$result = $function($ii, $item);
if (false === $result) {
// skip other filters, continue to next item.
continue;
}
$nextCollection->push($item);
}
$currentCollection = $nextCollection;
}
return $currentCollection;
}
/** /**
* Same as getGroups but everything is in a paginator. * Same as getGroups but everything is in a paginator.
* *
@@ -269,19 +580,21 @@ class GroupCollector implements GroupCollectorInterface
} }
/** /**
* Has attachments * Limit the number of returned entries.
*
* @param int $limit
* *
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function hasAttachments(): GroupCollectorInterface public function setLimit(int $limit): GroupCollectorInterface
{ {
Log::debug('Add filter on attachment ID.'); $this->limit = $limit;
$this->joinAttachmentTables(); app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
$this->query->whereNotNull('attachments.attachable_id');
return $this; return $this;
} }
/** /**
* Limit results to a specific currency, either foreign or normal one. * Limit results to a specific currency, either foreign or normal one.
* *
@@ -346,21 +659,6 @@ class GroupCollector implements GroupCollectorInterface
return $this; return $this;
} }
/**
* Limit the number of returned entries.
*
* @param int $limit
*
* @return GroupCollectorInterface
*/
public function setLimit(int $limit): GroupCollectorInterface
{
$this->limit = $limit;
app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
return $this;
}
/** /**
* Set the page to get. * Set the page to get.
* *
@@ -456,55 +754,6 @@ class GroupCollector implements GroupCollectorInterface
return $this; return $this;
} }
/**
* Automatically include all stuff required to make API calls work.
*
* @return GroupCollectorInterface
*/
public function withAPIInformation(): GroupCollectorInterface
{
// include source + destination account name and type.
$this->withAccountInformation()
// include category ID + name (if any)
->withCategoryInformation()
// include budget ID + name (if any)
->withBudgetInformation()
// include bill ID + name (if any)
->withBillInformation();
return $this;
}
/**
* @inheritDoc
*/
public function withAttachmentInformation(): GroupCollectorInterface
{
$this->fields[] = 'attachments.id as attachment_id';
$this->joinAttachmentTables();
return $this;
}
/**
* Join table to get attachment information.
*/
private function joinAttachmentTables(): void
{
if (false === $this->hasJoinedAttTables) {
// join some extra tables:
$this->hasJoinedAttTables = true;
$this->query->leftJoin('attachments', 'attachments.attachable_id', '=', 'transaction_journals.id')
->where(
static function (EloquentBuilder $q1) {
$q1->where('attachments.attachable_type', TransactionJournal::class);
$q1->where('attachments.uploaded', true);
$q1->orWhereNull('attachments.attachable_type');
}
);
}
}
/** /**
* Build the query. * Build the query.
*/ */
@@ -549,241 +798,21 @@ class GroupCollector implements GroupCollectorInterface
} }
/** /**
* Automatically include all stuff required to make API calls work.
* *
* @return GroupCollectorInterface
*/ */
public function dumpQuery(): void public function withAPIInformation(): GroupCollectorInterface
{ {
echo $this->query->select($this->fields)->toSql(); // include source + destination account name and type.
echo '<pre>'; $this->withAccountInformation()
print_r($this->query->getBindings()); // include category ID + name (if any)
echo '</pre>'; ->withCategoryInformation()
} // include budget ID + name (if any)
->withBudgetInformation()
// include bill ID + name (if any)
->withBillInformation();
/** return $this;
*
*/
public function dumpQueryInLogs(): void
{
Log::debug($this->query->select($this->fields)->toSql()) ;
Log::debug('Bindings',$this->query->getBindings());
}
/**
* Convert a selected set of fields to arrays.
*
* @param array $array
*
* @return array
*/
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
}
return $array;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeAttachments(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int)$newJournal['tag_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
];
}
return $existingJournal;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeTags(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int)$newJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($newArray['tag_date']);
} catch (InvalidDateException $e) {
Log::debug(sprintf('Could not parse date: %s', $e->getMessage()));
}
$existingJournal['tags'][$tagId] = [
'id' => (int)$newArray['tag_id'],
'name' => $newArray['tag_name'],
'date' => $tagDate,
'description' => $newArray['tag_description'],
];
}
return $existingJournal;
}
/**
* @param Collection $collection
*
* @return Collection
*/
private function parseArray(Collection $collection): Collection
{
$groups = [];
/** @var TransactionJournal $augumentedJournal */
foreach ($collection as $augumentedJournal) {
$groupId = $augumentedJournal->transaction_group_id;
if (!array_key_exists($groupId, $groups)) {
// make new array
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
$groupArray = [
'id' => (int)$augumentedJournal->transaction_group_id,
'user_id' => (int)$augumentedJournal->user_id,
'title' => $augumentedJournal->transaction_group_title,
'transaction_type' => $parsedGroup['transaction_type_type'],
'count' => 1,
'sums' => [],
'transactions' => [],
];
$journalId = (int)$augumentedJournal->transaction_journal_id;
$groupArray['transactions'][$journalId] = $parsedGroup;
$groups[$groupId] = $groupArray;
continue;
}
// or parse the rest.
$journalId = (int)$augumentedJournal->transaction_journal_id;
if (array_key_exists($journalId, $groups[$groupId]['transactions'])) {
// append data to existing group + journal (for multiple tags or multiple attachments)
$groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
$groups[$groupId]['transactions'][$journalId] = $this->mergeAttachments($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
}
if (!array_key_exists($journalId, $groups[$groupId]['transactions'])) {
// create second, third, fourth split:
$groups[$groupId]['count']++;
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal);
}
}
$groups = $this->parseSums($groups);
return new Collection($groups);
}
/**
* @param TransactionJournal $augumentedJournal
*
* @return array
*/
private function parseAugmentedJournal(TransactionJournal $augumentedJournal): array
{
$result = $augumentedJournal->toArray();
$result['tags'] = [];
$result['attachments'] = [];
try {
$result['date'] = new Carbon($result['date'], 'UTC');
$result['created_at'] = new Carbon($result['created_at'], 'UTC');
$result['updated_at'] = new Carbon($result['updated_at'], 'UTC');
// this is going to happen a lot:
$result['date']->setTimezone(config('app.timezone'));
$result['created_at']->setTimezone(config('app.timezone'));
$result['updated_at']->setTimezone(config('app.timezone'));
} catch (Exception $e) { // @phpstan-ignore-line
Log::error($e->getMessage());
}
// convert values to integers:
$result = $this->convertToInteger($result);
$result['reconciled'] = 1 === (int)$result['reconciled'];
if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well.
$tagId = (int)$augumentedJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($augumentedJournal['tag_date']);
} catch (InvalidDateException $e) {
Log::debug(sprintf('Could not parse date: %s', $e->getMessage()));
}
$result['tags'][$tagId] = [
'id' => (int)$result['tag_id'],
'name' => $result['tag_name'],
'date' => $tagDate,
'description' => $result['tag_description'],
];
}
// also merge attachments:
if (array_key_exists('attachment_id', $result)) {
$attachmentId = (int)$augumentedJournal['attachment_id'];
if (0 !== $attachmentId) {
$result['attachments'][$attachmentId] = [
'id' => $attachmentId,
];
}
}
return $result;
}
/**
* @param array $groups
*
* @return array
*/
private function parseSums(array $groups): array
{
/**
* @var int $groudId
* @var array $group
*/
foreach ($groups as $groudId => $group) {
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
$currencyId = (int)$transaction['currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
$groups[$groudId]['sums'][$currencyId]['currency_id'] = $currencyId;
$groups[$groudId]['sums'][$currencyId]['currency_code'] = $transaction['currency_code'];
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount'] ?? '0');
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int)$transaction['foreign_currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
$groups[$groudId]['sums'][$currencyId]['currency_id'] = $currencyId;
$groups[$groudId]['sums'][$currencyId]['currency_code'] = $transaction['foreign_currency_code'];
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['foreign_currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['foreign_currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd(
$groups[$groudId]['sums'][$currencyId]['amount'],
$transaction['foreign_amount'] ?? '0'
);
}
}
}
return $groups;
} }
} }

View File

@@ -58,7 +58,7 @@ interface GroupCollectorInterface
public function amountLess(string $amount): GroupCollectorInterface; public function amountLess(string $amount): GroupCollectorInterface;
/** /**
* Get transactions where the amount is more than. * Get transactions where the foreign amount is more than.
* *
* @param string $amount * @param string $amount
* *
@@ -66,6 +66,72 @@ interface GroupCollectorInterface
*/ */
public function amountMore(string $amount): GroupCollectorInterface; public function amountMore(string $amount): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameContains(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameEnds(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameIs(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameStarts(string $name): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesAre(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesContains(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesEnds(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesStarts(string $value): GroupCollectorInterface;
/**
* @param string $day
* @return GroupCollectorInterface
*/
public function dayAfter(string $day): GroupCollectorInterface;
/**
* @param string $day
* @return GroupCollectorInterface
*/
public function dayBefore(string $day): GroupCollectorInterface;
/**
* @param string $day
* @return GroupCollectorInterface
*/
public function dayIs(string $day): GroupCollectorInterface;
/** /**
* End of the description must match: * End of the description must match:
* *
@@ -111,6 +177,42 @@ interface GroupCollectorInterface
*/ */
public function excludeSourceAccounts(Collection $accounts): GroupCollectorInterface; public function excludeSourceAccounts(Collection $accounts): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function externalIdContains(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function externalIdEnds(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function externalIdStarts(string $externalId): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlContains(string $url): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlEnds(string $url): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlStarts(string $url): GroupCollectorInterface;
/** /**
* Ensure the search will find nothing at all, zero results. * Ensure the search will find nothing at all, zero results.
* *
@@ -118,6 +220,33 @@ interface GroupCollectorInterface
*/ */
public function findNothing(): GroupCollectorInterface; public function findNothing(): GroupCollectorInterface;
/**
* Get transactions with a specific foreign amount.
*
* @param string $amount
*
* @return GroupCollectorInterface
*/
public function foreignAmountIs(string $amount): GroupCollectorInterface;
/**
* Get transactions where the amount is less than.
*
* @param string $amount
*
* @return GroupCollectorInterface
*/
public function foreignAmountLess(string $amount): GroupCollectorInterface;
/**
* Get transactions where the foreign amount is more than.
*
* @param string $amount
*
* @return GroupCollectorInterface
*/
public function foreignAmountMore(string $amount): GroupCollectorInterface;
/** /**
* Return the transaction journals without group information. Is useful in some instances. * Return the transaction journals without group information. Is useful in some instances.
* *
@@ -151,6 +280,112 @@ interface GroupCollectorInterface
*/ */
public function hasAttachments(): GroupCollectorInterface; public function hasAttachments(): GroupCollectorInterface;
/**
* Has no attachments
*
* @return GroupCollectorInterface
*/
public function hasNoAttachments(): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function internalReferenceContains(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function internalReferenceEnds(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function internalReferenceStarts(string $externalId): GroupCollectorInterface;
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function metaDayAfter(string $day, string $field): GroupCollectorInterface;
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function metaDayBefore(string $day, string $field): GroupCollectorInterface;
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function metaDayIs(string $day, string $field): GroupCollectorInterface;
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function metaMonthAfter(string $month, string $field): GroupCollectorInterface;
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function metaMonthBefore(string $month, string $field): GroupCollectorInterface;
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function metaMonthIs(string $month, string $field): GroupCollectorInterface;
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function metaYearAfter(string $year, string $field): GroupCollectorInterface;
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function metaYearBefore(string $year, string $field): GroupCollectorInterface;
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function metaYearIs(string $year, string $field): GroupCollectorInterface;
/**
* @param string $month
* @return GroupCollectorInterface
*/
public function monthAfter(string $month): GroupCollectorInterface;
/**
* @param string $month
* @return GroupCollectorInterface
*/
public function monthBefore(string $month): GroupCollectorInterface;
/**
* @param string $month
* @return GroupCollectorInterface
*/
public function monthIs(string $month): GroupCollectorInterface;
/** /**
* @param string $value * @param string $value
* *
@@ -179,6 +414,69 @@ interface GroupCollectorInterface
*/ */
public function notesStartWith(string $value): GroupCollectorInterface; public function notesStartWith(string $value): GroupCollectorInterface;
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function objectDayAfter(string $day, string $field): GroupCollectorInterface;
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function objectDayBefore(string $day, string $field): GroupCollectorInterface;
/**
* @param string $day
* @param string $field
* @return GroupCollectorInterface
*/
public function objectDayIs(string $day, string $field): GroupCollectorInterface;
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function objectMonthAfter(string $month, string $field): GroupCollectorInterface;
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function objectMonthBefore(string $month, string $field): GroupCollectorInterface;
/**
* @param string $month
* @param string $field
* @return GroupCollectorInterface
*/
public function objectMonthIs(string $month, string $field): GroupCollectorInterface;
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function objectYearAfter(string $year, string $field): GroupCollectorInterface;
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function objectYearBefore(string $year, string $field): GroupCollectorInterface;
/**
* @param string $year
* @param string $field
* @return GroupCollectorInterface
*/
public function objectYearIs(string $year, string $field): GroupCollectorInterface;
/** /**
* Define which accounts can be part of the source and destination transactions. * Define which accounts can be part of the source and destination transactions.
* *
@@ -306,18 +604,10 @@ interface GroupCollectorInterface
public function setExternalId(string $externalId): GroupCollectorInterface; public function setExternalId(string $externalId): GroupCollectorInterface;
/** /**
* Transactions without an external URL * @param string $url
*
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function withoutExternalUrl(): GroupCollectorInterface; public function setExternalUrl(string $url): GroupCollectorInterface;
/**
* Transactions with an external URL
*
* @return GroupCollectorInterface
*/
public function withExternalUrl(): GroupCollectorInterface;
/** /**
* Limit results to a specific foreign currency. * Limit results to a specific foreign currency.
@@ -364,6 +654,57 @@ interface GroupCollectorInterface
*/ */
public function setLimit(int $limit): GroupCollectorInterface; public function setLimit(int $limit): GroupCollectorInterface;
/**
* Collect transactions after a specific date.
*
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setMetaAfter(Carbon $date, string $field): GroupCollectorInterface;
/**
* Collect transactions before a specific date.
*
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setMetaBefore(Carbon $date, string $field): GroupCollectorInterface;
/**
* Set the start and end time of the results to return, based on meta data.
*
* @param Carbon $start
* @param Carbon $end
* @param string $field
*
* @return GroupCollectorInterface
*/
public function setMetaDateRange(Carbon $start, Carbon $end, string $field): GroupCollectorInterface;
/**
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setObjectAfter(Carbon $date, string $field): GroupCollectorInterface;
/**
* @param Carbon $date
* @param string $field
* @return GroupCollectorInterface
*/
public function setObjectBefore(Carbon $date, string $field): GroupCollectorInterface;
/**
* @param Carbon $start
* @param Carbon $end
* @param string $field
* @return GroupCollectorInterface
*/
public function setObjectRange(Carbon $start, Carbon $end, string $field): GroupCollectorInterface;
/** /**
* Set the page to get. * Set the page to get.
* *
@@ -383,6 +724,15 @@ interface GroupCollectorInterface
*/ */
public function setRange(Carbon $start, Carbon $end): GroupCollectorInterface; public function setRange(Carbon $start, Carbon $end): GroupCollectorInterface;
/**
* Look for specific recurring ID's.
*
* @param string $recurringId
*
* @return GroupCollectorInterface
*/
public function setRecurrenceId(string $recurringId): GroupCollectorInterface;
/** /**
* Search for words in descriptions. * Search for words in descriptions.
* *
@@ -455,6 +805,15 @@ interface GroupCollectorInterface
*/ */
public function setUser(User $user): GroupCollectorInterface; public function setUser(User $user): GroupCollectorInterface;
/**
* Only when does not have these tags
*
* @param Collection $tags
*
* @return GroupCollectorInterface
*/
public function setWithoutSpecificTags(Collection $tags): GroupCollectorInterface;
/** /**
* Either account can be set, but NOT both. This effectively excludes internal transfers. * Either account can be set, but NOT both. This effectively excludes internal transfers.
* *
@@ -534,6 +893,21 @@ interface GroupCollectorInterface
*/ */
public function withCategoryInformation(): GroupCollectorInterface; public function withCategoryInformation(): GroupCollectorInterface;
/**
* Transactions with an external URL
*
* @return GroupCollectorInterface
*/
public function withExternalUrl(): GroupCollectorInterface;
/**
* Transaction must have meta date field X.
*
* @param string $field
* @return GroupCollectorInterface
*/
public function withMetaDate(string $field): GroupCollectorInterface;
/** /**
* Will include notes. * Will include notes.
* *
@@ -569,6 +943,13 @@ interface GroupCollectorInterface
*/ */
public function withoutCategory(): GroupCollectorInterface; public function withoutCategory(): GroupCollectorInterface;
/**
* Transactions without an external URL
*
* @return GroupCollectorInterface
*/
public function withoutExternalUrl(): GroupCollectorInterface;
/** /**
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
@@ -579,15 +960,23 @@ interface GroupCollectorInterface
*/ */
public function withoutTags(): GroupCollectorInterface; public function withoutTags(): GroupCollectorInterface;
/**
public function yearIs(string $year): GroupCollectorInterface; * @param string $year
public function monthIs(string $month): GroupCollectorInterface; * @return GroupCollectorInterface
public function dayIs(string $day): GroupCollectorInterface; */
public function yearBefore(string $year): GroupCollectorInterface;
public function monthBefore(string $month): GroupCollectorInterface;
public function dayBefore(string $day): GroupCollectorInterface;
public function yearAfter(string $year): GroupCollectorInterface; public function yearAfter(string $year): GroupCollectorInterface;
public function monthAfter(string $month): GroupCollectorInterface;
public function dayAfter(string $day): GroupCollectorInterface; /**
* @param string $year
* @return GroupCollectorInterface
*/
public function yearBefore(string $year): GroupCollectorInterface;
/**
* @param string $year
* @return GroupCollectorInterface
*/
public function yearIs(string $year): GroupCollectorInterface;
} }

View File

@@ -46,6 +46,9 @@ class FiscalHelper implements FiscalHelperInterface
* @param Carbon $date * @param Carbon $date
* *
* @return Carbon date object * @return Carbon date object
* @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function endOfFiscalYear(Carbon $date): Carbon public function endOfFiscalYear(Carbon $date): Carbon
{ {
@@ -69,6 +72,8 @@ class FiscalHelper implements FiscalHelperInterface
* *
* @return Carbon date object * @return Carbon date object
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function startOfFiscalYear(Carbon $date): Carbon public function startOfFiscalYear(Carbon $date): Carbon
{ {

View File

@@ -1,163 +0,0 @@
<?php
/**
* Help.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Help;
use Cache;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use League\CommonMark\CommonMarkConverter;
use Log;
use Route;
/**
* Class Help.
*/
class Help implements HelpInterface
{
/** @var string The cache key */
public const CACHEKEY = 'help_%s_%s';
/** @var string The user agent. */
protected $userAgent = 'Firefly III v%s';
/**
* Constructor.
*/
public function __construct()
{
$this->userAgent = sprintf($this->userAgent, config('firefly.version'));
}
/**
* Get from cache.
*
* @codeCoverageIgnore
*
* @param string $route
* @param string $language
*
* @return string
*/
public function getFromCache(string $route, string $language): string
{
$line = sprintf(self::CACHEKEY, $route, $language);
return Cache::get($line);
}
/**
* Get text from GitHub.
*
* @param string $route
* @param string $language
*
* @return string
* @throws GuzzleException
*/
public function getFromGitHub(string $route, string $language): string
{
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/main/%s/%s.md', $language, $route);
Log::debug(sprintf('Trying to get %s...', $uri));
$opt = ['headers' => ['User-Agent' => $this->userAgent]];
$content = '';
$statusCode = 500;
$client = app(Client::class);
try {
$res = $client->request('GET', $uri, $opt);
$statusCode = $res->getStatusCode();
$content = trim($res->getBody()->getContents());
} catch (Exception $e) { // @phpstan-ignore-line
Log::info($e->getMessage());
//Log::info($e->getTraceAsString());
}
Log::debug(sprintf('Status code is %d', $statusCode));
if ('' !== $content) {
Log::debug('Content is longer than zero. Expect something.');
$converter = new CommonMarkConverter();
$content = (string)$converter->convertToHtml($content);
}
return $content;
}
/**
* Do we have the route?
*
* @codeCoverageIgnore
*
* @param string $route
*
* @return bool
*/
public function hasRoute(string $route): bool
{
return Route::has($route);
}
/**
* Is in cache?
*
* @codeCoverageIgnore
*
* @param string $route
* @param string $language
*
* @return bool
*/
public function inCache(string $route, string $language): bool
{
$line = sprintf(self::CACHEKEY, $route, $language);
$result = Cache::has($line);
if ($result) {
Log::debug(sprintf('Cache has this entry: %s', 'help.' . $route . '.' . $language));
}
if (!$result) {
Log::debug(sprintf('Cache does not have this entry: %s', 'help.' . $route . '.' . $language));
}
return $result;
}
/**
* Put help text in cache.
*
* @codeCoverageIgnore
*
* @param string $route
* @param string $language
* @param string $content
*/
public function putInCache(string $route, string $language, string $content): void
{
$key = sprintf(self::CACHEKEY, $route, $language);
if ('' !== $content) {
Log::debug(sprintf('Will store entry in cache: %s', $key));
Cache::put($key, $content, 10080); // a week.
return;
}
Log::info(sprintf('Will not cache %s because content is empty.', $key));
}
}

View File

@@ -1,77 +0,0 @@
<?php
/**
* HelpInterface.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Help;
/**
* Interface HelpInterface.
*/
interface HelpInterface
{
/**
* Get the help text from cache.
*
* @param string $route
* @param string $language
*
* @return string
*/
public function getFromCache(string $route, string $language): string;
/**
* Get the help text from GitHub.
*
* @param string $route
* @param string $language
*
* @return string
*/
public function getFromGitHub(string $route, string $language): string;
/**
* Is the route a known route?
*
* @param string $route
*
* @return bool
*/
public function hasRoute(string $route): bool;
/**
* Is the help text in cache?
*
* @param string $route
* @param string $language
*
* @return bool
*/
public function inCache(string $route, string $language): bool;
/**
* Put the result in cache.
*
* @param string $route
* @param string $language
* @param string $content
*/
public function putInCache(string $route, string $language, string $content);
}

View File

@@ -31,7 +31,6 @@ use FireflyIII\Support\CacheProperties;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use JsonException; use JsonException;
use Log;
/** /**
* *
@@ -64,6 +63,7 @@ class NetWorth implements NetWorthInterface
* *
* @return array * @return array
* @throws JsonException * @throws JsonException
* @throws \FireflyIII\Exceptions\FireflyException
*/ */
public function getNetWorthByCurrency(Collection $accounts, Carbon $date): array public function getNetWorthByCurrency(Collection $accounts, Carbon $date): array
{ {

View File

@@ -141,7 +141,7 @@ class ReportHelper implements ReportHelperInterface
$currentEnd = clone $start; $currentEnd = clone $start;
$currentEnd->endOfMonth(); $currentEnd->endOfMonth();
$months[$year]['months'][] = [ $months[$year]['months'][] = [
'formatted' => $start->formatLocalized('%B %Y'), 'formatted' => $start->isoFormat((string) trans('config.month_js')),
'start' => $start->format('Y-m-d'), 'start' => $start->format('Y-m-d'),
'end' => $currentEnd->format('Y-m-d'), 'end' => $currentEnd->format('Y-m-d'),
'month' => $start->month, 'month' => $start->month,

View File

@@ -40,6 +40,8 @@ trait UpdateTrait
* *
* @return array * @return array
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function getLatestRelease(): array public function getLatestRelease(): array
{ {

View File

@@ -137,6 +137,8 @@ class CreateController extends Controller
* *
* @return RedirectResponse|Redirector * @return RedirectResponse|Redirector
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function store(AccountFormRequest $request) public function store(AccountFormRequest $request)
{ {

View File

@@ -74,6 +74,9 @@ class IndexController extends Controller
* *
* @return Factory|View * @return Factory|View
* @throws FireflyException * @throws FireflyException
* @throws \JsonException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function inactive(Request $request, string $objectType) public function inactive(Request $request, string $objectType)
{ {
@@ -128,7 +131,10 @@ class IndexController extends Controller
* @param string $objectType * @param string $objectType
* *
* @return Factory|View * @return Factory|View
* @throws Exception * @throws FireflyException
* @throws \JsonException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function index(Request $request, string $objectType) public function index(Request $request, string $objectType)
{ {

View File

@@ -86,7 +86,10 @@ class ReconcileController extends Controller
* @param Carbon|null $end * @param Carbon|null $end
* *
* @return Factory|RedirectResponse|Redirector|View * @return Factory|RedirectResponse|Redirector|View
* @throws Exception * @throws FireflyException
* @throws \JsonException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function reconcile(Account $account, Carbon $start = null, Carbon $end = null) public function reconcile(Account $account, Carbon $start = null, Carbon $end = null)
{ {
@@ -237,7 +240,8 @@ class ReconcileController extends Controller
// title: // title:
$description = trans( $description = trans(
'firefly.reconciliation_transaction_title', 'firefly.reconciliation_transaction_title',
['from' => $start->formatLocalized($this->monthAndDayFormat), 'to' => $end->formatLocalized($this->monthAndDayFormat)] ['from' => $start->isoFormat($this->monthAndDayFormat),
'to' => $end->isoFormat($this->monthAndDayFormat)]
); );
$submission = [ $submission = [
'user' => auth()->user()->id, 'user' => auth()->user()->id,

View File

@@ -83,8 +83,10 @@ class ShowController extends Controller
* @param Carbon|null $end * @param Carbon|null $end
* *
* @return RedirectResponse|Redirector|Factory|View * @return RedirectResponse|Redirector|Factory|View
* @throws Exception * @throws \FireflyIII\Exceptions\FireflyException
* * @throws \JsonException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null) public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
{ {
@@ -109,8 +111,8 @@ class ShowController extends Controller
$page = (int) $request->get('page'); $page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data; $pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); $currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$fStart = $start->formatLocalized($this->monthAndDayFormat); $fStart = $start->isoFormat($this->monthAndDayFormat);
$fEnd = $end->formatLocalized($this->monthAndDayFormat); $fEnd = $end->isoFormat($this->monthAndDayFormat);
$subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]); $subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); $chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$firstTransaction = $this->repository->oldestJournalDate($account) ?? $start; $firstTransaction = $this->repository->oldestJournalDate($account) ?? $start;
@@ -164,8 +166,10 @@ class ShowController extends Controller
* @param Account $account * @param Account $account
* *
* @return RedirectResponse|Redirector|Factory|View * @return RedirectResponse|Redirector|Factory|View
* @throws Exception * @throws \FireflyIII\Exceptions\FireflyException
* * @throws \JsonException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function showAll(Request $request, Account $account) public function showAll(Request $request, Account $account)
{ {

View File

@@ -61,6 +61,8 @@ class ConfigurationController extends Controller
* *
* @return Factory|View * @return Factory|View
* @throws FireflyException * @throws FireflyException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/ */
public function index() public function index()
{ {

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