mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-17 03:14:34 +00:00
Compare commits
152 Commits
6.0.0-alph
...
6.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
|
86d6a2f581 | ||
|
df4f28e819 | ||
|
9ee66625de | ||
|
fb595bb335 | ||
|
a8e4fbb7b6 | ||
|
0060c46cdb | ||
|
b909841eae | ||
|
f001675066 | ||
|
c979cfcd89 | ||
|
2a30b10b97 | ||
|
fb903d5e3a | ||
|
268f690d75 | ||
|
2e074009c4 | ||
|
d5e60b206d | ||
|
1964afe876 | ||
|
328a476fb5 | ||
|
12ca0811e6 | ||
|
7a20f7ce34 | ||
|
cce856c0e2 | ||
|
5ef2a33334 | ||
|
6e29a7421f | ||
|
89e6bd7471 | ||
|
df0a6db83f | ||
|
c949ff19b7 | ||
|
e4b4234fbb | ||
|
86aaa3068a | ||
|
08f9da8a15 | ||
|
6bd0aa14b3 | ||
|
38bff09c1d | ||
|
93caa433d7 | ||
|
bcb1fce7ed | ||
|
c777c95ced | ||
|
5e89bde05b | ||
|
79e98cf8a2 | ||
|
bf8ab7f5d7 | ||
|
54a471ba4c | ||
|
26accbc81e | ||
|
242c6c1b0c | ||
|
db659efe27 | ||
|
06be3f0d46 | ||
|
da318fb592 | ||
|
d58c230f00 | ||
|
fd7ba9dd57 | ||
|
47a98451a0 | ||
|
91e961a876 | ||
|
9aaf79a3ab | ||
|
b1e3cf3a20 | ||
|
be0d785a56 | ||
|
efb89023ac | ||
|
9adccb345a | ||
|
83f5b8ab12 | ||
|
de38e7cf9f | ||
|
3a0b3f46a5 | ||
|
806d108d1c | ||
|
794d130ff9 | ||
|
848e7d4c9f | ||
|
6e96c75be7 | ||
|
e20dc78620 | ||
|
35912fe9fb | ||
|
74777a648c | ||
|
0eb0f7f35f | ||
|
1226ef542f | ||
|
7d169518a5 | ||
|
abfd837f68 | ||
|
8ab1e97fb0 | ||
|
9fbb290d0f | ||
|
28deb32f5e | ||
|
2c1023ad40 | ||
|
766418a894 | ||
|
970193473d | ||
|
a782abd6db | ||
|
b98050e238 | ||
|
1c02b04a0d | ||
|
c5f94372a0 | ||
|
928613e908 | ||
|
fd3da949da | ||
|
15210f75e7 | ||
|
dec5e3440d | ||
|
413a4f3d9c | ||
|
1cbb644d65 | ||
|
e008c1f742 | ||
|
9bffa86706 | ||
|
a5a95055c5 | ||
|
5a5c92b5b5 | ||
|
41941b37f9 | ||
|
881fe3e6e7 | ||
|
a7570d9ab5 | ||
|
605afdb271 | ||
|
b6e54fe3cf | ||
|
fbe5a5dd39 | ||
|
e284da368d | ||
|
a5328a9ff4 | ||
|
a925e1aa02 | ||
|
81c37b3349 | ||
|
c84c64a1c2 | ||
|
ced9ea4777 | ||
|
36c0e8df2d | ||
|
61a0a7795e | ||
|
e2b4448985 | ||
|
f5d1a597cf | ||
|
80607bc6ae | ||
|
8c5c6c2bde | ||
|
f476a909df | ||
|
9bf86be305 | ||
|
3d96f5df58 | ||
|
fc0adfd375 | ||
|
1d62d5d44a | ||
|
6c2486faa7 | ||
|
f9daf7751a | ||
|
c269913510 | ||
|
cc436605d0 | ||
|
c697d2aa13 | ||
|
90219bec35 | ||
|
afca023767 | ||
|
1502c5de94 | ||
|
cd408e581b | ||
|
122c8acae0 | ||
|
13cffaa1e3 | ||
|
feab244edd | ||
|
259ad852c9 | ||
|
6802f53c96 | ||
|
d922390802 | ||
|
2a9f51a40f | ||
|
614d54c9bd | ||
|
3ea8792c6e | ||
|
3d802b9c9e | ||
|
480d787242 | ||
|
820c6feadd | ||
|
8c1eeedf17 | ||
|
9b5931f1d6 | ||
|
d5cade320b | ||
|
ef46ab6de2 | ||
|
d0d3921ff6 | ||
|
2cb2e2e635 | ||
|
1a0047205d | ||
|
468655cd94 | ||
|
09cb4b10b9 | ||
|
6eaf83d6d2 | ||
|
7c8a2e3591 | ||
|
ba5c3ef0a1 | ||
|
c0f744b03a | ||
|
8cd13ba13b | ||
|
10db3d63ac | ||
|
a753fde2f1 | ||
|
d4f1b9a1bc | ||
|
3cfaa5aa03 | ||
|
bc47017e31 | ||
|
125d9e7e9d | ||
|
4cea7a3287 | ||
|
e7a1ad23f4 | ||
|
afd3fd9f88 | ||
|
f2251d7bfa |
@@ -60,7 +60,7 @@ APP_LOG_LEVEL=info
|
||||
# Use "pgsql" for PostgreSQL
|
||||
# Use "mysql" for MySQL and MariaDB.
|
||||
# Use "sqlite" for SQLite.
|
||||
DB_CONNECTION=sqlite_test
|
||||
DB_CONNECTION=sqlite
|
||||
|
||||
# MySQL supports SSL. You can configure it here.
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
@@ -127,7 +127,6 @@ MAIL_ENCRYPTION=null
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
|
||||
# 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
|
||||
MAILGUN_ENDPOINT=api.mailgun.net
|
||||
@@ -136,7 +135,6 @@ MAILGUN_ENDPOINT=api.mailgun.net
|
||||
MANDRILL_SECRET=
|
||||
SPARKPOST_SECRET=
|
||||
|
||||
|
||||
# Firefly III can send you the following messages
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
@@ -223,7 +221,6 @@ ADLDAP_ADMIN_PASSWORD=
|
||||
ADLDAP_ACCOUNT_PREFIX=
|
||||
ADLDAP_ACCOUNT_SUFFIX=
|
||||
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=false
|
||||
ADLDAP_LOGIN_FALLBACK=false
|
||||
|
237
.ci/php-cs-fixer/composer.lock
generated
237
.ci/php-cs-fixer/composer.lock
generated
@@ -226,30 +226,30 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "1.14.2",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b"
|
||||
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/ad785217c1e9555a7d6c6c8c9f406395a5e2882b",
|
||||
"reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/lexer": "^1 || ^2",
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"psr/cache": "^1 || ^2 || ^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "^1.11 || ^2.0",
|
||||
"doctrine/coding-standard": "^9 || ^10",
|
||||
"phpstan/phpstan": "~1.4.10 || ^1.8.0",
|
||||
"doctrine/cache": "^2.0",
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.8.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6",
|
||||
"symfony/cache": "^5.4 || ^6",
|
||||
"vimeo/psalm": "^4.10"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -296,77 +296,33 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/annotations/issues",
|
||||
"source": "https://github.com/doctrine/annotations/tree/1.14.2"
|
||||
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
|
||||
},
|
||||
"time": "2022-12-15T06:48:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/deprecations.git",
|
||||
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
|
||||
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"phpunit/phpunit": "^7.5|^8.5|^9.5",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
|
||||
"homepage": "https://www.doctrine-project.org/",
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||
"source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
|
||||
},
|
||||
"time": "2022-05-02T15:47:09+00:00"
|
||||
"time": "2023-02-02T22:02:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"version": "2.1.0",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/lexer.git",
|
||||
"reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124"
|
||||
"reference": "84a527db05647743d50373e0ec53a152f2cde568"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
|
||||
"reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568",
|
||||
"reference": "84a527db05647743d50373e0ec53a152f2cde568",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^1.0",
|
||||
"php": "^7.1 || ^8.0"
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9 || ^10",
|
||||
"phpstan/phpstan": "^1.3",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-phpunit": "^0.18.3",
|
||||
"vimeo/psalm": "^4.11 || ^5.0"
|
||||
"vimeo/psalm": "^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -403,7 +359,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/lexer/issues",
|
||||
"source": "https://github.com/doctrine/lexer/tree/2.1.0"
|
||||
"source": "https://github.com/doctrine/lexer/tree/3.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -419,55 +375,56 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-14T08:49:07+00:00"
|
||||
"time": "2022-12-15T16:57:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.13.2",
|
||||
"version": "v3.14.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496"
|
||||
"reference": "1b3d9dba63d93b8a202c31e824748218781eae6b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/3952f08a81bd3b1b15e11c3de0b6bf037faa8496",
|
||||
"reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1b3d9dba63d93b8a202c31e824748218781eae6b",
|
||||
"reference": "1b3d9dba63d93b8a202c31e824748218781eae6b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/semver": "^3.2",
|
||||
"composer/semver": "^3.3",
|
||||
"composer/xdebug-handler": "^3.0.3",
|
||||
"doctrine/annotations": "^1.13",
|
||||
"doctrine/annotations": "^2",
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"sebastian/diff": "^4.0",
|
||||
"sebastian/diff": "^4.0 || ^5.0",
|
||||
"symfony/console": "^5.4 || ^6.0",
|
||||
"symfony/event-dispatcher": "^5.4 || ^6.0",
|
||||
"symfony/filesystem": "^5.4 || ^6.0",
|
||||
"symfony/finder": "^5.4 || ^6.0",
|
||||
"symfony/options-resolver": "^5.4 || ^6.0",
|
||||
"symfony/polyfill-mbstring": "^1.23",
|
||||
"symfony/polyfill-php80": "^1.25",
|
||||
"symfony/polyfill-php81": "^1.25",
|
||||
"symfony/polyfill-mbstring": "^1.27",
|
||||
"symfony/polyfill-php80": "^1.27",
|
||||
"symfony/polyfill-php81": "^1.27",
|
||||
"symfony/process": "^5.4 || ^6.0",
|
||||
"symfony/stopwatch": "^5.4 || ^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"justinrainbow/json-schema": "^5.2",
|
||||
"keradus/cli-executor": "^2.0",
|
||||
"mikey179/vfsstream": "^1.6.10",
|
||||
"php-coveralls/php-coveralls": "^2.5.2",
|
||||
"mikey179/vfsstream": "^1.6.11",
|
||||
"php-coveralls/php-coveralls": "^2.5.3",
|
||||
"php-cs-fixer/accessible-object": "^1.1",
|
||||
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
|
||||
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1",
|
||||
"phpspec/prophecy": "^1.15",
|
||||
"phpspec/prophecy": "^1.16",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"phpunitgoodpractices/polyfill": "^1.6",
|
||||
"phpunitgoodpractices/traits": "^1.9.2",
|
||||
"symfony/phpunit-bridge": "^6.0",
|
||||
"symfony/phpunit-bridge": "^6.2.3",
|
||||
"symfony/yaml": "^5.4 || ^6.0"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -500,7 +457,7 @@
|
||||
"description": "A tool to automatically fix PHP code style",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.13.2"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.14.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -508,7 +465,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-02T23:53:50+00:00"
|
||||
"time": "2023-02-09T21:49:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
@@ -714,29 +671,29 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "4.0.4",
|
||||
"version": "5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
|
||||
"reference": "70dd1b20bc198da394ad542e988381b44e64e39f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
|
||||
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/70dd1b20bc198da394ad542e988381b44e64e39f",
|
||||
"reference": "70dd1b20bc198da394ad542e988381b44e64e39f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.3"
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"symfony/process": "^4.2 || ^5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0-dev"
|
||||
"dev-main": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -768,7 +725,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/5.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -776,20 +733,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T13:10:38+00:00"
|
||||
"time": "2023-02-03T07:00:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.2.3",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "0f579613e771dba2dbb8211c382342a641f5da06"
|
||||
"reference": "3e294254f2191762c1d137aed4b94e966965e985"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0f579613e771dba2dbb8211c382342a641f5da06",
|
||||
"reference": "0f579613e771dba2dbb8211c382342a641f5da06",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/3e294254f2191762c1d137aed4b94e966965e985",
|
||||
"reference": "3e294254f2191762c1d137aed4b94e966965e985",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -856,7 +813,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.2.3"
|
||||
"source": "https://github.com/symfony/console/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -872,7 +829,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-28T14:26:22+00:00"
|
||||
"time": "2023-01-01T08:38:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -943,16 +900,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v6.2.2",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "3ffeb31139b49bf6ef0bc09d1db95eac053388d1"
|
||||
"reference": "f02d108b5e9fd4a6245aa73a9d2df2ec060c3e68"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3ffeb31139b49bf6ef0bc09d1db95eac053388d1",
|
||||
"reference": "3ffeb31139b49bf6ef0bc09d1db95eac053388d1",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f02d108b5e9fd4a6245aa73a9d2df2ec060c3e68",
|
||||
"reference": "f02d108b5e9fd4a6245aa73a9d2df2ec060c3e68",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1006,7 +963,7 @@
|
||||
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v6.2.2"
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1022,7 +979,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-14T16:11:27+00:00"
|
||||
"time": "2023-01-01T08:38:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
@@ -1105,16 +1062,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v6.2.0",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "50b2523c874605cf3d4acf7a9e2b30b6a440a016"
|
||||
"reference": "e59e8a4006afd7f5654786a83b4fcb8da98f4593"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/50b2523c874605cf3d4acf7a9e2b30b6a440a016",
|
||||
"reference": "50b2523c874605cf3d4acf7a9e2b30b6a440a016",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e59e8a4006afd7f5654786a83b4fcb8da98f4593",
|
||||
"reference": "e59e8a4006afd7f5654786a83b4fcb8da98f4593",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1148,7 +1105,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.2.0"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1164,20 +1121,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-20T13:01:27+00:00"
|
||||
"time": "2023-01-20T17:45:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v6.2.3",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "81eefbddfde282ee33b437ba5e13d7753211ae8e"
|
||||
"reference": "c90dc446976a612e3312a97a6ec0069ab0c2099c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/81eefbddfde282ee33b437ba5e13d7753211ae8e",
|
||||
"reference": "81eefbddfde282ee33b437ba5e13d7753211ae8e",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/c90dc446976a612e3312a97a6ec0069ab0c2099c",
|
||||
"reference": "c90dc446976a612e3312a97a6ec0069ab0c2099c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1212,7 +1169,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v6.2.3"
|
||||
"source": "https://github.com/symfony/finder/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1228,20 +1185,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-22T17:55:15+00:00"
|
||||
"time": "2023-01-20T17:45:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v6.2.0",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "d28f02acde71ff75e957082cd36e973df395f626"
|
||||
"reference": "e8324d44f5af99ec2ccec849934a242f64458f86"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28f02acde71ff75e957082cd36e973df395f626",
|
||||
"reference": "d28f02acde71ff75e957082cd36e973df395f626",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/e8324d44f5af99ec2ccec849934a242f64458f86",
|
||||
"reference": "e8324d44f5af99ec2ccec849934a242f64458f86",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1279,7 +1236,7 @@
|
||||
"options"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v6.2.0"
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1295,7 +1252,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-02T09:08:04+00:00"
|
||||
"time": "2023-01-01T08:38:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -1791,16 +1748,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v6.2.0",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "ba6e55359f8f755fe996c58a81e00eaa67a35877"
|
||||
"reference": "9ead139f63dfa38c4e4a9049cc64a8b2748c83b7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/ba6e55359f8f755fe996c58a81e00eaa67a35877",
|
||||
"reference": "ba6e55359f8f755fe996c58a81e00eaa67a35877",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/9ead139f63dfa38c4e4a9049cc64a8b2748c83b7",
|
||||
"reference": "9ead139f63dfa38c4e4a9049cc64a8b2748c83b7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1832,7 +1789,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v6.2.0"
|
||||
"source": "https://github.com/symfony/process/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1848,7 +1805,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-02T09:08:04+00:00"
|
||||
"time": "2023-01-01T08:38:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -1937,16 +1894,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/stopwatch",
|
||||
"version": "v6.2.0",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/stopwatch.git",
|
||||
"reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7"
|
||||
"reference": "00b6ac156aacffc53487c930e0ab14587a6607f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/266636bb8f3fbdccc302491df7b3a1b9a8c238a7",
|
||||
"reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/00b6ac156aacffc53487c930e0ab14587a6607f6",
|
||||
"reference": "00b6ac156aacffc53487c930e0ab14587a6607f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1979,7 +1936,7 @@
|
||||
"description": "Provides a way to profile code",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/stopwatch/tree/v6.2.0"
|
||||
"source": "https://github.com/symfony/stopwatch/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1995,20 +1952,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-28T16:00:52+00:00"
|
||||
"time": "2023-01-01T08:36:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v6.2.2",
|
||||
"version": "v6.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "863219fd713fa41cbcd285a79723f94672faff4d"
|
||||
"reference": "b2dac0fa27b1ac0f9c0c0b23b43977f12308d0b0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/863219fd713fa41cbcd285a79723f94672faff4d",
|
||||
"reference": "863219fd713fa41cbcd285a79723f94672faff4d",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/b2dac0fa27b1ac0f9c0c0b23b43977f12308d0b0",
|
||||
"reference": "b2dac0fa27b1ac0f9c0c0b23b43977f12308d0b0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2065,7 +2022,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v6.2.2"
|
||||
"source": "https://github.com/symfony/string/tree/v6.2.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2081,7 +2038,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-14T16:11:27+00:00"
|
||||
"time": "2023-01-01T08:38:09+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@@ -19,15 +19,43 @@
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
# enable test .env file.
|
||||
cp .ci/.env.ci ../.env
|
||||
cp $SCRIPT_DIR/../.env $SCRIPT_DIR/../.env.backup
|
||||
cp $SCRIPT_DIR/.env.ci $SCRIPT_DIR/../.env
|
||||
|
||||
COVERAGE=false
|
||||
RESET=false
|
||||
FILE=storage/database/database.sqlite
|
||||
|
||||
while getopts "cr" o; do
|
||||
case "${o}" in
|
||||
c) COVERAGE=true;;
|
||||
r) RESET=true;;
|
||||
esac
|
||||
done
|
||||
|
||||
# reset if necessary.
|
||||
if [ $RESET = "true" ] ; then
|
||||
rm -f $FILE
|
||||
fi
|
||||
|
||||
# download test database
|
||||
# TODO no longer exists
|
||||
wget --quiet https://raw.githubusercontent.com/firefly-iii/test-data/main/test_db.sqlite -o storage/database/test_db.sqlite
|
||||
if [ -f "$FILE" ]; then
|
||||
echo 'DB exists, will use it'
|
||||
else
|
||||
echo 'Download new DB'
|
||||
wget --quiet https://github.com/firefly-iii/test-fixtures/raw/main/test-database.sqlite -O $FILE
|
||||
fi
|
||||
|
||||
# run phpunit
|
||||
./vendor/bin/phpunit --configuration phpunit.coverage.xml
|
||||
if [ $COVERAGE = "true" ] ; then
|
||||
echo 'Run with coverage'
|
||||
XDEBUG_MODE=coverage ./vendor/bin/phpunit --configuration phpunit.xml --coverage-html $SCRIPT_DIR/coverage
|
||||
else
|
||||
echo 'Run without coverage'
|
||||
./vendor/bin/phpunit --configuration phpunit.xml
|
||||
fi
|
||||
|
||||
exit 0
|
||||
# restore .env file
|
||||
mv $SCRIPT_DIR/../.env.backup $SCRIPT_DIR/../.env
|
||||
|
@@ -158,9 +158,7 @@ MANDRILL_SECRET=
|
||||
SPARKPOST_SECRET=
|
||||
|
||||
# Firefly III can send you the following messages.
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
SEND_LOGIN_NEW_IP_WARNING=true
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=true
|
||||
|
57
.github/mergify.yml
vendored
57
.github/mergify.yml
vendored
@@ -1,3 +1,4 @@
|
||||
---
|
||||
pull_request_rules:
|
||||
- name: Close all on main
|
||||
conditions:
|
||||
@@ -5,4 +6,58 @@ pull_request_rules:
|
||||
- -author~=^dependabot(|-preview)\[bot\]$
|
||||
actions:
|
||||
close:
|
||||
message: Please do not open PR's on the `main` branch, but on the `develop` branch only. Thank you!
|
||||
message: Please do not open PR's on the `main` branch, but on the `develop`
|
||||
branch only. Thank you!
|
||||
- name: No translations
|
||||
conditions:
|
||||
- -author~=^dependabot(|-preview)\[bot\]$
|
||||
- base=develop
|
||||
- or:
|
||||
- files~=^resources/lang/bg_BG
|
||||
- files~=^resources/lang/ca_ES
|
||||
- files~=^resources/lang/cs_CZ
|
||||
- files~=^resources/lang/da_DK
|
||||
- files~=^resources/lang/de_DE
|
||||
- files~=^resources/lang/el_GR
|
||||
- files~=^resources/lang/en_GB
|
||||
- files~=^resources/lang/es_ES
|
||||
- files~=^resources/lang/et_EE
|
||||
- files~=^resources/lang/fa_IR
|
||||
- files~=^resources/lang/fi_FI
|
||||
- files~=^resources/lang/fr_FR
|
||||
- files~=^resources/lang/he_IL
|
||||
- files~=^resources/lang/hu_HU
|
||||
- files~=^resources/lang/id_ID
|
||||
- files~=^resources/lang/is_IS
|
||||
- files~=^resources/lang/it_IT
|
||||
- files~=^resources/lang/ja_JP
|
||||
- files~=^resources/lang/ko_KR
|
||||
- files~=^resources/lang/lt_LT
|
||||
- files~=^resources/lang/nb_NO
|
||||
- files~=^resources/lang/nl_NL
|
||||
- files~=^resources/lang/pl_PL
|
||||
- files~=^resources/lang/pt_BR
|
||||
- files~=^resources/lang/pt_PT
|
||||
- files~=^resources/lang/ro_RO
|
||||
- files~=^resources/lang/ru_RU
|
||||
- files~=^resources/lang/si_LK
|
||||
- files~=^resources/lang/sk_SK
|
||||
- files~=^resources/lang/sl_SI
|
||||
- files~=^resources/lang/sr_CS
|
||||
- files~=^resources/lang/sv_SE
|
||||
- files~=^resources/lang/th_TH
|
||||
- files~=^resources/lang/tlh_AA
|
||||
- files~=^resources/lang/tr_TR
|
||||
- files~=^resources/lang/uk_UA
|
||||
- files~=^resources/lang/vi_VN
|
||||
- files~=^resources/lang/zh_CN
|
||||
- files~=^resources/lang/zh_TW
|
||||
actions:
|
||||
comment:
|
||||
message: >
|
||||
Please do not submit translated strings in your PR. If you need new
|
||||
sentences to be translated, add them to the `en_US` language strings.
|
||||
New or changed translations for other languages can be submitted at
|
||||
https://crowdin.com/project/firefly-iii
|
||||
|
||||
Thank you!
|
||||
|
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -1,12 +1,6 @@
|
||||
name: Sonarcloud CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- 5.8-dev
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
sonarcloud:
|
||||
name: SonarCloud
|
||||
@@ -19,4 +13,4 @@ jobs:
|
||||
uses: SonarSource/sonarcloud-github-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
29
.github/workflows/qodana.yml
vendored
Normal file
29
.github/workflows/qodana.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Qodana
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
jobs:
|
||||
qodana:
|
||||
runs-on: ubuntu-latest
|
||||
name: 'Qodana Scan'
|
||||
steps:
|
||||
- name: Setup PHP with no coverage driver
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.2'
|
||||
coverage: none
|
||||
extensions: bcmath, intl
|
||||
env:
|
||||
update: true
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
- name: 'Qodana Scan'
|
||||
uses: JetBrains/qodana-action@main
|
||||
env:
|
||||
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ npm-debug.log
|
||||
yarn-error.log
|
||||
.env
|
||||
/.ci/php-cs-fixer/vendor
|
||||
/.ci/coverage
|
||||
|
@@ -31,10 +31,12 @@ use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
@@ -95,14 +97,20 @@ abstract class Controller extends BaseController
|
||||
// some date fields:
|
||||
$dates = ['start', 'end', 'date'];
|
||||
foreach ($dates as $field) {
|
||||
$date = request()->query->get($field);
|
||||
$obj = null;
|
||||
try {
|
||||
$date = request()->query->get($field);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
}
|
||||
$obj = null;
|
||||
if (null !== $date) {
|
||||
try {
|
||||
$obj = Carbon::parse($date);
|
||||
} catch (InvalidDateException|InvalidFormatException $e) {
|
||||
// don't care
|
||||
app('log')->warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', $date, $e->getMessage()));
|
||||
app('log')->warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', substr($date, 0, 20), $e->getMessage()));
|
||||
}
|
||||
}
|
||||
$bag->set($field, $obj);
|
||||
@@ -111,7 +119,13 @@ abstract class Controller extends BaseController
|
||||
// integer fields:
|
||||
$integers = ['limit'];
|
||||
foreach ($integers as $integer) {
|
||||
$value = request()->query->get($integer);
|
||||
try {
|
||||
$value = request()->query->get($integer);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
}
|
||||
if (null !== $value) {
|
||||
$bag->set($integer, (int)$value);
|
||||
}
|
||||
@@ -129,7 +143,13 @@ abstract class Controller extends BaseController
|
||||
private function getSortParameters(ParameterBag $bag): ParameterBag
|
||||
{
|
||||
$sortParameters = [];
|
||||
$param = (string)request()->query->get('sort');
|
||||
try {
|
||||
$param = (string)request()->query->get('sort');
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.');
|
||||
Log::error($e->getMessage());
|
||||
$param = '';
|
||||
}
|
||||
if ('' === $param) {
|
||||
return $bag;
|
||||
}
|
||||
|
@@ -69,7 +69,7 @@ class DestroyController extends Controller
|
||||
$this->unused = $request->boolean('unused', false);
|
||||
switch ($objects) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('This endpoint can\'t handle object "%s"', $objects));
|
||||
throw new FireflyException(sprintf('200033: This endpoint can\'t handle object "%s"', $objects));
|
||||
case 'budgets':
|
||||
$this->destroyBudgets();
|
||||
break;
|
||||
|
@@ -28,8 +28,10 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Class DestroyController
|
||||
@@ -37,6 +39,7 @@ use Illuminate\Http\JsonResponse;
|
||||
class DestroyController extends Controller
|
||||
{
|
||||
private CurrencyRepositoryInterface $repository;
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
/**
|
||||
* CurrencyRepository constructor.
|
||||
@@ -49,6 +52,7 @@ class DestroyController extends Controller
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(CurrencyRepositoryInterface::class);
|
||||
$this->userRepository = app(UserRepositoryInterface::class);
|
||||
$this->repository->setUser(auth()->user());
|
||||
|
||||
return $next($request);
|
||||
@@ -72,16 +76,20 @@ class DestroyController extends Controller
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$rules = ['currency_code' => 'required'];
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
// access denied:
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.');
|
||||
$messages = ['currency_code' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
if ($this->repository->currencyInUse($currency)) {
|
||||
throw new FireflyException('200006: Currency in use.');
|
||||
$messages = ['currency_code' => '200006: Currency in use.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
if ($this->repository->isFallbackCurrency($currency)) {
|
||||
throw new FireflyException('200026: Currency is fallback.');
|
||||
$messages = ['currency_code' => '200026: Currency is fallback.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
|
||||
$this->repository->destroy($currency);
|
||||
|
@@ -34,6 +34,7 @@ use FireflyIII\Transformers\LinkTypeTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Class StoreController
|
||||
@@ -81,9 +82,12 @@ class StoreController extends Controller
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$rules = ['name' => 'required'];
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.');
|
||||
// access denied:
|
||||
$messages = ['name' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
$data = $request->getAll();
|
||||
// if currency ID is 0, find the currency by the code:
|
||||
|
@@ -35,6 +35,7 @@ use FireflyIII\Transformers\LinkTypeTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Class UpdateController
|
||||
@@ -87,9 +88,11 @@ class UpdateController extends Controller
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$rules = ['name' => 'required'];
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.');
|
||||
$messages = ['name' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
|
||||
$data = $request->getAll();
|
||||
|
@@ -350,11 +350,11 @@ class BasicController extends Controller
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$date = Carbon::now()->startOfDay();
|
||||
$date = today(config('app.timezone'))->startOfDay();
|
||||
// start and end in the future? use $end
|
||||
if ($this->notInDateRange($date, $start, $end)) {
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', Carbon::now()->endOfMonth());
|
||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
}
|
||||
|
||||
/** @var NetWorthInterface $netWorthHelper */
|
||||
|
@@ -32,6 +32,7 @@ use Illuminate\Http\JsonResponse;
|
||||
use Log;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Class ConfigurationController
|
||||
@@ -174,8 +175,10 @@ class ConfigurationController extends Controller
|
||||
*/
|
||||
public function update(UpdateRequest $request, string $name): JsonResponse
|
||||
{
|
||||
$rules = ['value' => 'required'];
|
||||
if (!$this->repository->hasRole(auth()->user(), 'owner')) {
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.');
|
||||
$messages = ['value' => '200005: You need the "owner" role to do this.'];
|
||||
Validator::make([], $rules, $messages)->validate();
|
||||
}
|
||||
$data = $request->getAll();
|
||||
$shortName = str_replace('configuration.', '', $name);
|
||||
|
@@ -73,7 +73,7 @@ class AttemptController extends Controller
|
||||
public function index(Webhook $webhook, WebhookMessage $message): JsonResponse
|
||||
{
|
||||
if ($message->webhook_id !== $webhook->id) {
|
||||
throw new FireflyException('Webhook and webhook message are no match');
|
||||
throw new FireflyException('200040: Webhook and webhook message are no match');
|
||||
}
|
||||
|
||||
$manager = $this->getManager();
|
||||
@@ -112,10 +112,10 @@ class AttemptController extends Controller
|
||||
public function show(Webhook $webhook, WebhookMessage $message, WebhookAttempt $attempt): JsonResponse
|
||||
{
|
||||
if ($message->webhook_id !== $webhook->id) {
|
||||
throw new FireflyException('Webhook and webhook message are no match');
|
||||
throw new FireflyException('200040: Webhook and webhook message are no match');
|
||||
}
|
||||
if ($attempt->webhook_message_id !== $message->id) {
|
||||
throw new FireflyException('Webhook message and webhook attempt are no match');
|
||||
throw new FireflyException('200041: Webhook message and webhook attempt are no match');
|
||||
}
|
||||
|
||||
$manager = $this->getManager();
|
||||
|
@@ -91,10 +91,10 @@ class DestroyController extends Controller
|
||||
public function destroyAttempt(Webhook $webhook, WebhookMessage $message, WebhookAttempt $attempt): JsonResponse
|
||||
{
|
||||
if ($message->webhook_id !== $webhook->id) {
|
||||
throw new FireflyException('Webhook and webhook message are no match');
|
||||
throw new FireflyException('200040: Webhook and webhook message are no match');
|
||||
}
|
||||
if ($attempt->webhook_message_id !== $message->id) {
|
||||
throw new FireflyException('Webhook message and webhook attempt are no match');
|
||||
throw new FireflyException('200041: Webhook message and webhook attempt are no match');
|
||||
}
|
||||
|
||||
$this->repository->destroyAttempt($attempt);
|
||||
@@ -119,7 +119,7 @@ class DestroyController extends Controller
|
||||
public function destroyMessage(Webhook $webhook, WebhookMessage $message): JsonResponse
|
||||
{
|
||||
if ($message->webhook_id !== $webhook->id) {
|
||||
throw new FireflyException('Webhook and webhook message are no match');
|
||||
throw new FireflyException('200040: Webhook and webhook message are no match');
|
||||
}
|
||||
$this->repository->destroyMessage($message);
|
||||
app('preferences')->mark();
|
||||
|
@@ -103,7 +103,7 @@ class MessageController extends Controller
|
||||
public function show(Webhook $webhook, WebhookMessage $message): JsonResponse
|
||||
{
|
||||
if ($message->webhook_id !== $webhook->id) {
|
||||
throw new FireflyException('Webhook and webhook message are no match');
|
||||
throw new FireflyException('200040: Webhook and webhook message are no match');
|
||||
}
|
||||
|
||||
$manager = $this->getManager();
|
||||
|
@@ -42,8 +42,8 @@ class ExportRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
$result = [
|
||||
'start' => $this->getCarbonDate('start') ?? Carbon::now()->subYear(),
|
||||
'end' => $this->getCarbonDate('end') ?? Carbon::now(),
|
||||
'start' => $this->getCarbonDate('start') ?? today(config('app.timezone'))->subYear(),
|
||||
'end' => $this->getCarbonDate('end') ?? today(config('app.timezone')),
|
||||
'type' => $this->convertString('type'),
|
||||
];
|
||||
$parts = explode(',', $this->convertString('accounts'));
|
||||
|
@@ -83,8 +83,6 @@ class StoreRequest extends FormRequest
|
||||
$data = $this->appendLocationData($data, null);
|
||||
|
||||
if ('liability' === $data['account_type_name'] || 'liabilities' === $data['account_type_name']) {
|
||||
$data['opening_balance'] = app('steam')->negative($this->convertString('liability_amount'));
|
||||
$data['opening_balance_date'] = $this->getCarbonDate('liability_start_date');
|
||||
$data['account_type_name'] = $this->convertString('liability_type');
|
||||
$data['liability_direction'] = $this->convertString('liability_direction');
|
||||
$data['account_type_id'] = null;
|
||||
|
@@ -76,22 +76,8 @@ class UpdateRequest extends FormRequest
|
||||
'liability_amount' => ['liability_amount', 'convertString'],
|
||||
'liability_start_date' => ['liability_start_date', 'date'],
|
||||
];
|
||||
/** @var Account $account */
|
||||
$account = $this->route()->parameter('account');
|
||||
$data = $this->getAllData($fields);
|
||||
$data = $this->appendLocationData($data, null);
|
||||
$valid = config('firefly.valid_liabilities');
|
||||
if (array_key_exists('liability_amount', $data) && in_array($account->accountType->type, $valid, true)) {
|
||||
$data['opening_balance'] = app('steam')->negative($data['liability_amount']);
|
||||
Log::debug(sprintf('Opening balance for liability is "%s".', $data['opening_balance']));
|
||||
}
|
||||
|
||||
if (array_key_exists('liability_start_date', $data) && in_array($account->accountType->type, $valid, true)) {
|
||||
$data['opening_balance_date'] = $data['liability_start_date'];
|
||||
Log::debug(sprintf('Opening balance date for liability is "%s".', $data['opening_balance_date']));
|
||||
}
|
||||
|
||||
return $data;
|
||||
return $this->appendLocationData($data, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -56,7 +56,7 @@ class CronRequest extends FormRequest
|
||||
{
|
||||
$data = [
|
||||
'force' => false,
|
||||
'date' => Carbon::now(),
|
||||
'date' => today(config('app.timezone')),
|
||||
];
|
||||
if ($this->has('force')) {
|
||||
$data['force'] = $this->boolean('force');
|
||||
|
@@ -32,6 +32,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
@@ -39,6 +40,7 @@ use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
@@ -90,14 +92,20 @@ class Controller extends BaseController
|
||||
|
||||
// some date fields:
|
||||
foreach ($dates as $field) {
|
||||
$date = request()->query->get($field);
|
||||
$obj = null;
|
||||
try {
|
||||
$date = request()->query->get($field);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
}
|
||||
$obj = null;
|
||||
if (null !== $date) {
|
||||
try {
|
||||
$obj = Carbon::parse($date);
|
||||
} catch (InvalidDateException|InvalidFormatException $e) {
|
||||
// don't care
|
||||
app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', $date, $e->getMessage()));
|
||||
app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr($date, 0, 20), $e->getMessage()));
|
||||
}
|
||||
}
|
||||
$bag->set($field, $obj);
|
||||
@@ -105,7 +113,13 @@ class Controller extends BaseController
|
||||
|
||||
// integer fields:
|
||||
foreach ($integers as $integer) {
|
||||
$value = request()->query->get($integer);
|
||||
try {
|
||||
$value = request()->query->get($integer);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
}
|
||||
if (null !== $value) {
|
||||
$bag->set($integer, (int)$value);
|
||||
}
|
||||
|
@@ -139,17 +139,17 @@ class FixTransactionTypes extends Command
|
||||
}
|
||||
);
|
||||
if (0 === $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has no source transaction.', $journal->id));
|
||||
throw new FireflyException(sprintf('300001: Journal #%d has no source transaction.', $journal->id));
|
||||
}
|
||||
if (1 !== $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has multiple source transactions.', $journal->id));
|
||||
throw new FireflyException(sprintf('300002: Journal #%d has multiple source transactions.', $journal->id));
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $collection->first();
|
||||
/** @var Account|null $account */
|
||||
$account = $transaction->account;
|
||||
if (null === $account) {
|
||||
throw new FireflyException(sprintf('Journal #%d, transaction #%d has no source account.', $journal->id, $transaction->id));
|
||||
throw new FireflyException(sprintf('300003: Journal #%d, transaction #%d has no source account.', $journal->id, $transaction->id));
|
||||
}
|
||||
|
||||
return $account;
|
||||
@@ -169,17 +169,17 @@ class FixTransactionTypes extends Command
|
||||
}
|
||||
);
|
||||
if (0 === $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has no destination transaction.', $journal->id));
|
||||
throw new FireflyException(sprintf('300004: Journal #%d has no destination transaction.', $journal->id));
|
||||
}
|
||||
if (1 !== $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has multiple destination transactions.', $journal->id));
|
||||
throw new FireflyException(sprintf('300005: Journal #%d has multiple destination transactions.', $journal->id));
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $collection->first();
|
||||
/** @var Account|null $account */
|
||||
$account = $transaction->account;
|
||||
if (null === $account) {
|
||||
throw new FireflyException(sprintf('Journal #%d, transaction #%d has no destination account.', $journal->id, $transaction->id));
|
||||
throw new FireflyException(sprintf('300006: Journal #%d, transaction #%d has no destination account.', $journal->id, $transaction->id));
|
||||
}
|
||||
|
||||
return $account;
|
||||
|
@@ -191,7 +191,7 @@ class ExportData extends Command
|
||||
*/
|
||||
private function getDateParameter(string $field): Carbon
|
||||
{
|
||||
$date = Carbon::now()->subYear();
|
||||
$date = today(config('app.timezone'))->subYear();
|
||||
$error = false;
|
||||
if (null !== $this->option($field)) {
|
||||
try {
|
||||
@@ -209,7 +209,7 @@ class ExportData extends Command
|
||||
|
||||
if (true === $error && 'start' === $field) {
|
||||
$journal = $this->journalRepository->firstNull();
|
||||
$date = null === $journal ? Carbon::now()->subYear() : $journal->date;
|
||||
$date = null === $journal ? today(config('app.timezone'))->subYear() : $journal->date;
|
||||
$date->startOfDay();
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ class ExportData extends Command
|
||||
}
|
||||
}
|
||||
if (0 === $final->count()) {
|
||||
throw new FireflyException('Ended up with zero valid accounts to export from.');
|
||||
throw new FireflyException('300007: Ended up with zero valid accounts to export from.');
|
||||
}
|
||||
|
||||
return $final;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* CreateGroupMemberships.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Upgrade;
|
||||
namespace FireflyIII\Console\Commands\Integrity;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\GroupMembership;
|
||||
@@ -31,8 +31,6 @@ use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class CreateGroupMemberships
|
||||
@@ -51,7 +49,7 @@ class CreateGroupMemberships extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:create-group-memberships {--F|force : Force the execution of this command.}';
|
||||
protected $signature = 'firefly-iii:create-group-memberships';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
@@ -62,36 +60,15 @@ class CreateGroupMemberships extends Command
|
||||
public function handle(): int
|
||||
{
|
||||
$start = microtime(true);
|
||||
if ($this->isExecuted() && true !== $this->option('force')) {
|
||||
$this->warn('This command has already been executed.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
$this->createGroupMemberships();
|
||||
$this->markAsExecuted();
|
||||
|
||||
$end = round(microtime(true) - $start, 2);
|
||||
$this->info(sprintf('in %s seconds.', $end));
|
||||
$this->info(sprintf('Validated group memberships in %s seconds.', $end));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws FireflyException
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function isExecuted(): bool
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws FireflyException
|
||||
@@ -102,24 +79,11 @@ class CreateGroupMemberships extends Command
|
||||
/** @var User $user */
|
||||
foreach ($users as $user) {
|
||||
Log::debug(sprintf('Manage group memberships for user #%d', $user->id));
|
||||
if (!$this->hasGroupMembership($user)) {
|
||||
Log::debug(sprintf('User #%d has no main group.', $user->id));
|
||||
$this->createGroupMembership($user);
|
||||
}
|
||||
$this->createGroupMembership($user);
|
||||
Log::debug(sprintf('Done with user #%d', $user->id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasGroupMembership(User $user): bool
|
||||
{
|
||||
return $user->groupMemberships()->count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
@@ -127,35 +91,37 @@ class CreateGroupMemberships extends Command
|
||||
*/
|
||||
private function createGroupMembership(User $user): void
|
||||
{
|
||||
$userGroup = UserGroup::create(['title' => $user->email]);
|
||||
$userRole = UserRole::where('title', UserRole::OWNER)->first();
|
||||
// check if membership exists
|
||||
$userGroup = UserGroup::where('title', $user->email)->first();
|
||||
if (null === $userGroup) {
|
||||
$userGroup = UserGroup::create(['title' => $user->email]);
|
||||
Log::debug(sprintf('Created new user group #%d ("%s")', $userGroup->id, $userGroup->title));
|
||||
}
|
||||
|
||||
$userRole = UserRole::where('title', UserRole::OWNER)->first();
|
||||
|
||||
if (null === $userRole) {
|
||||
throw new FireflyException('Firefly III could not find a user role. Please make sure all validations have run.');
|
||||
throw new FireflyException('Firefly III could not find a user role. Please make sure all migrations have run.');
|
||||
}
|
||||
|
||||
/** @var GroupMembership|null $membership */
|
||||
$membership = GroupMembership::create(
|
||||
[
|
||||
'user_id' => $user->id,
|
||||
'user_role_id' => $userRole->id,
|
||||
'user_group_id' => $userGroup->id,
|
||||
]
|
||||
);
|
||||
$membership = GroupMembership::where('user_id', $user->id)
|
||||
->where('user_group_id', $userGroup->id)
|
||||
->where('user_role_id', $userRole->id)->first();
|
||||
if (null === $membership) {
|
||||
throw new FireflyException('Firefly III could not create user group management object. Please make sure all validations have run.');
|
||||
GroupMembership::create(
|
||||
[
|
||||
'user_id' => $user->id,
|
||||
'user_role_id' => $userRole->id,
|
||||
'user_group_id' => $userGroup->id,
|
||||
]
|
||||
);
|
||||
Log::debug('Created new membership.');
|
||||
}
|
||||
if (null === $user->user_group_id) {
|
||||
$user->user_group_id = $userGroup->id;
|
||||
$user->save();
|
||||
Log::debug('Put user in default group.');
|
||||
}
|
||||
$user->user_group_id = $userGroup->id;
|
||||
$user->save();
|
||||
|
||||
Log::debug(sprintf('User #%d now has main group.', $user->id));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
@@ -282,7 +282,7 @@ class ApplyRules extends Command
|
||||
private function verifyInputDates(): void
|
||||
{
|
||||
// parse start date.
|
||||
$inputStart = Carbon::now()->startOfMonth();
|
||||
$inputStart = today(config('app.timezone'))->startOfMonth();
|
||||
$startString = $this->option('start_date');
|
||||
if (null === $startString) {
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
@@ -298,7 +298,7 @@ class ApplyRules extends Command
|
||||
}
|
||||
|
||||
// parse end date
|
||||
$inputEnd = Carbon::now();
|
||||
$inputEnd = today(config('app.timezone'));
|
||||
$endString = $this->option('end_date');
|
||||
if (null !== $endString && '' !== $endString) {
|
||||
$inputEnd = Carbon::createFromFormat('Y-m-d', $endString);
|
||||
|
@@ -74,7 +74,6 @@ class UpgradeDatabase extends Command
|
||||
'firefly-iii:migrate-tag-locations',
|
||||
'firefly-iii:migrate-recurrence-type',
|
||||
'firefly-iii:upgrade-liabilities',
|
||||
'firefly-iii:create-group-memberships',
|
||||
'firefly-iii:liabilities-600',
|
||||
|
||||
// there are 16 verify commands.
|
||||
@@ -100,6 +99,7 @@ class UpgradeDatabase extends Command
|
||||
'firefly-iii:fix-transaction-types',
|
||||
'firefly-iii:fix-frontpage-accounts',
|
||||
'firefly-iii:fix-ibans',
|
||||
'firefly-iii:create-group-memberships',
|
||||
'firefly-iii:upgrade-group-information',
|
||||
|
||||
// two report commands
|
||||
|
@@ -48,7 +48,7 @@ trait VerifiesAccessToken
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
$user = $repository->find($userId);
|
||||
if (null === $user) {
|
||||
throw new FireflyException('User is unexpectedly NULL');
|
||||
throw new FireflyException('300000: User is unexpectedly NULL');
|
||||
}
|
||||
|
||||
return $user;
|
||||
|
@@ -168,7 +168,7 @@ class Handler extends ExceptionHandler
|
||||
return response()->view('errors.FireflyException', ['exception' => $e, 'debug' => $isDebug], 500);
|
||||
}
|
||||
|
||||
Log::debug('Error has no Firefly III treatment, parent will handle.');
|
||||
Log::debug(sprintf('Error "%s" has no Firefly III treatment, parent will handle.', get_class($e)));
|
||||
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ class PiggyBankEventHandler
|
||||
if (null !== $event->transactionGroup) {
|
||||
$journal = $event->transactionGroup->transactionJournals()->first();
|
||||
}
|
||||
$date = $journal?->date ?? Carbon::now();
|
||||
$date = $journal?->date ?? today(config('app.timezone'));
|
||||
|
||||
// sanity check: event must not already exist for this journal and piggy bank.
|
||||
if (null !== $journal) {
|
||||
|
@@ -73,12 +73,12 @@ class NetWorth implements NetWorthInterface
|
||||
$cache->addProperty('net-worth-by-currency');
|
||||
$cache->addProperty(implode(',', $accounts->pluck('id')->toArray()));
|
||||
if ($cache->has()) {
|
||||
// return $cache->get();
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
$netWorth = [];
|
||||
$result = [];
|
||||
Log::debug(sprintf('Now in getNetWorthByCurrency(%s)', $date->format('Y-m-d')));
|
||||
// Log::debug(sprintf('Now in getNetWorthByCurrency(%s)', $date->format('Y-m-d')));
|
||||
|
||||
// get default currency
|
||||
$default = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
@@ -89,16 +89,16 @@ class NetWorth implements NetWorthInterface
|
||||
// get the preferred currency for this account
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
Log::debug(sprintf('Now at account #%d: "%s"', $account->id, $account->name));
|
||||
// Log::debug(sprintf('Now at account #%d: "%s"', $account->id, $account->name));
|
||||
$currencyId = (int)$this->accountRepository->getMetaValue($account, 'currency_id');
|
||||
$currencyId = 0 === $currencyId ? $default->id : $currencyId;
|
||||
|
||||
Log::debug(sprintf('Currency ID is #%d', $currencyId));
|
||||
// Log::debug(sprintf('Currency ID is #%d', $currencyId));
|
||||
|
||||
// balance in array:
|
||||
$balance = $balances[$account->id] ?? '0';
|
||||
|
||||
Log::debug(sprintf('Balance for %s is %s', $date->format('Y-m-d'), $balance));
|
||||
//Log::debug(sprintf('Balance for %s is %s', $date->format('Y-m-d'), $balance));
|
||||
|
||||
// always subtract virtual balance.
|
||||
$virtualBalance = (string)$account->virtual_balance;
|
||||
@@ -106,14 +106,14 @@ class NetWorth implements NetWorthInterface
|
||||
$balance = bcsub($balance, $virtualBalance);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Balance corrected to %s because of virtual balance (%s)', $balance, $virtualBalance));
|
||||
// Log::debug(sprintf('Balance corrected to %s because of virtual balance (%s)', $balance, $virtualBalance));
|
||||
|
||||
if (!array_key_exists($currencyId, $netWorth)) {
|
||||
$netWorth[$currencyId] = '0';
|
||||
}
|
||||
$netWorth[$currencyId] = bcadd($balance, $netWorth[$currencyId]);
|
||||
|
||||
Log::debug(sprintf('Total net worth for currency #%d is %s', $currencyId, $netWorth[$currencyId]));
|
||||
// Log::debug(sprintf('Total net worth for currency #%d is %s', $currencyId, $netWorth[$currencyId]));
|
||||
}
|
||||
ksort($netWorth);
|
||||
|
||||
|
@@ -123,7 +123,7 @@ class ReportHelper implements ReportHelperInterface
|
||||
$fiscalHelper = app(FiscalHelperInterface::class);
|
||||
$start = clone $date;
|
||||
$start->startOfMonth();
|
||||
$end = Carbon::now();
|
||||
$end = today(config('app.timezone'));
|
||||
$end->endOfMonth();
|
||||
$months = [];
|
||||
|
||||
|
@@ -93,9 +93,9 @@ class IndexController extends Controller
|
||||
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
unset($collection);
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$start->subDay();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
@@ -156,9 +156,9 @@ class IndexController extends Controller
|
||||
|
||||
unset($collection);
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$start->subDay();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
|
@@ -100,7 +100,7 @@ class ReconcileController extends Controller
|
||||
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
|
||||
|
||||
// no start or end:
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(false);
|
||||
|
||||
// get start and end
|
||||
|
||||
|
@@ -182,7 +182,7 @@ class ShowController extends Controller
|
||||
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
|
||||
$end = today(config('app.timezone'));
|
||||
$today = today(config('app.timezone'));
|
||||
$start = $this->repository->oldestJournalDate($account) ?? Carbon::now()->startOfMonth();
|
||||
$start = $this->repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.'.$account->accountType->type);
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
|
@@ -154,7 +154,7 @@ class IndexController extends Controller
|
||||
private function getSums(array $bills): array
|
||||
{
|
||||
$sums = [];
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(false);
|
||||
|
||||
/** @var array $group */
|
||||
foreach ($bills as $groupOrder => $group) {
|
||||
|
@@ -104,8 +104,8 @@ class IndexController extends Controller
|
||||
Log::debug('Start of IndexController::index()');
|
||||
|
||||
// collect some basic vars:
|
||||
$range = (string)app('preferences')->get('viewRange', '1M')->data;
|
||||
$start = $start ?? session('start', Carbon::now()->startOfMonth());
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$start = $start ?? session('start', today(config('app.timezone'))->startOfMonth());
|
||||
$end = $end ?? app('navigation')->endOfPeriod($start, $range);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$currencies = $this->currencyRepository->get();
|
||||
|
@@ -159,7 +159,7 @@ class ShowController extends Controller
|
||||
public function show(Request $request, Budget $budget)
|
||||
{
|
||||
/** @var Carbon $allStart */
|
||||
$allStart = session('first', Carbon::now()->startOfYear());
|
||||
$allStart = session('first', today(config('app.timezone'))->startOfYear());
|
||||
$allEnd = today();
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
@@ -221,7 +221,7 @@ class ShowController extends Controller
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath(route('budgets.show', [$budget->id, $budgetLimit->id]));
|
||||
/** @var Carbon $start */
|
||||
$start = session('first', Carbon::now()->startOfYear());
|
||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||
$end = today(config('app.timezone'));
|
||||
$attachments = $this->repository->getAttachments($budget);
|
||||
$limits = $this->getLimits($budget, $start, $end);
|
||||
|
@@ -88,14 +88,14 @@ class ShowController extends Controller
|
||||
public function show(Request $request, Category $category, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start', Carbon::now()->startOfMonth());
|
||||
$start = $start ?? session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = $end ?? session('end', Carbon::now()->endOfMonth());
|
||||
$end = $end ?? session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$subTitleIcon = 'fa-bookmark';
|
||||
$page = (int)$request->get('page');
|
||||
$attachments = $this->repository->getAttachments($category);
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$oldest = $this->repository->firstUseDate($category) ?? Carbon::now()->startOfYear();
|
||||
$oldest = $this->repository->firstUseDate($category) ?? today(config('app.timezone'))->startOfYear();
|
||||
$periods = $this->getCategoryPeriodOverview($category, $oldest, $end);
|
||||
$path = route('categories.show', [$category->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$subTitle = trans(
|
||||
|
@@ -90,9 +90,9 @@ class AccountController extends Controller
|
||||
public function expenseAccounts(): JsonResponse
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
@@ -184,8 +184,8 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function expenseBudgetAll(AccountRepositoryInterface $repository, Account $account): JsonResponse
|
||||
{
|
||||
$start = $repository->oldestJournalDate($account) ?? Carbon::now()->startOfMonth();
|
||||
$end = Carbon::now();
|
||||
$start = $repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth();
|
||||
$end = today(config('app.timezone'));
|
||||
|
||||
return $this->expenseBudget($account, $start, $end);
|
||||
}
|
||||
@@ -259,8 +259,8 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function expenseCategoryAll(AccountRepositoryInterface $repository, Account $account): JsonResponse
|
||||
{
|
||||
$start = $repository->oldestJournalDate($account) ?? Carbon::now()->startOfMonth();
|
||||
$end = Carbon::now();
|
||||
$start = $repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth();
|
||||
$end = today(config('app.timezone'));
|
||||
|
||||
return $this->expenseCategory($account, $start, $end);
|
||||
}
|
||||
@@ -334,8 +334,8 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function frontpage(AccountRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$defaultSet = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray();
|
||||
Log::debug('Default set is ', $defaultSet);
|
||||
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
|
||||
@@ -360,8 +360,8 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function incomeCategoryAll(AccountRepositoryInterface $repository, Account $account): JsonResponse
|
||||
{
|
||||
$start = $repository->oldestJournalDate($account) ?? Carbon::now()->startOfMonth();
|
||||
$end = Carbon::now();
|
||||
$start = $repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth();
|
||||
$end = today(config('app.timezone'));
|
||||
|
||||
return $this->incomeCategory($account, $start, $end);
|
||||
}
|
||||
@@ -540,9 +540,9 @@ class AccountController extends Controller
|
||||
public function revenueAccounts(): JsonResponse
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
|
@@ -62,8 +62,8 @@ class BillController extends Controller
|
||||
*/
|
||||
public function frontpage(BillRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
|
@@ -214,7 +214,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($budgetLimitId);
|
||||
$cache->addProperty('chart.budget.expense-asset');
|
||||
$start = session('first', Carbon::now()->startOfYear());
|
||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||
$end = today();
|
||||
|
||||
if (null !== $budgetLimit) {
|
||||
@@ -282,7 +282,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($budgetLimitId);
|
||||
$cache->addProperty('chart.budget.expense-category');
|
||||
$start = session('first', Carbon::now()->startOfYear());
|
||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||
$end = today();
|
||||
if (null !== $budgetLimit) {
|
||||
$start = $budgetLimit->start_date;
|
||||
@@ -346,7 +346,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($budgetLimitId);
|
||||
$cache->addProperty('chart.budget.expense-expense');
|
||||
$start = session('first', Carbon::now()->startOfYear());
|
||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||
$end = today();
|
||||
if (null !== $budgetLimit) {
|
||||
$start = $budgetLimit->start_date;
|
||||
@@ -402,8 +402,8 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function frontpage(): JsonResponse
|
||||
{
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
|
@@ -89,7 +89,7 @@ class CategoryController extends Controller
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
$start = $repository->firstUseDate($category) ?? $this->getDate();
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(false);
|
||||
$start = app('navigation')->startOfPeriod($start, $range);
|
||||
$end = $this->getDate();
|
||||
|
||||
@@ -118,8 +118,8 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function frontPage(): JsonResponse
|
||||
{
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
@@ -293,7 +293,7 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function specificPeriod(Category $category, Carbon $date): JsonResponse
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(false);
|
||||
$start = app('navigation')->startOfPeriod($date, $range);
|
||||
$end = session()->get('end');
|
||||
if ($end < $start) {
|
||||
|
@@ -120,7 +120,7 @@ class DebugController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
// basic scope information:
|
||||
$now = Carbon::now()->format('Y-m-d H:i:s e');
|
||||
$now = today(config('app.timezone'))->format('Y-m-d H:i:s e');
|
||||
$buildNr = '(unknown)';
|
||||
$buildDate = '(unknown)';
|
||||
$expectedDBversion = config('firefly.db_version');
|
||||
|
@@ -119,9 +119,9 @@ class HomeController extends Controller
|
||||
$transactions = [];
|
||||
$frontPage = app('preferences')->getFresh('frontPageAccounts', $repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray());
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$accounts = $repository->getAccountsById($frontPage->data);
|
||||
$today = today(config('app.timezone'));
|
||||
|
||||
|
@@ -157,9 +157,9 @@ class JavascriptController extends Controller
|
||||
public function variablesV2(Request $request): Response
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
|
||||
$data = [
|
||||
'start' => $start->format('Y-m-d'),
|
||||
|
@@ -60,9 +60,9 @@ class BoxController extends Controller
|
||||
/** @var AvailableBudgetRepositoryInterface $abRepository */
|
||||
$abRepository = app(AvailableBudgetRepositoryInterface::class);
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$today = today(config('app.timezone'));
|
||||
$display = 2; // see method docs.
|
||||
$boxTitle = (string)trans('firefly.spent');
|
||||
@@ -135,9 +135,9 @@ class BoxController extends Controller
|
||||
{
|
||||
// Cache result, return cache if present.
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
@@ -216,12 +216,12 @@ class BoxController extends Controller
|
||||
*/
|
||||
public function netWorth(): JsonResponse
|
||||
{
|
||||
$date = Carbon::now()->endOfDay();
|
||||
$date = today(config('app.timezone'))->endOfDay();
|
||||
|
||||
// start and end in the future? use $end
|
||||
if ($this->notInSessionRange($date)) {
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', Carbon::now()->endOfMonth());
|
||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
}
|
||||
|
||||
/** @var NetWorthInterface $netWorthHelper */
|
||||
|
@@ -150,8 +150,9 @@ class RecurrenceController extends Controller
|
||||
*/
|
||||
public function suggest(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate(['date' => ['required', 'date'],]);
|
||||
$string = $request->get('date') ?? date('Y-m-d');
|
||||
$today = Carbon::now()->startOfDay();
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
$date = Carbon::createFromFormat('Y-m-d', $string)->startOfDay();
|
||||
$preSelected = (string)$request->get('pre_select');
|
||||
$locale = app('steam')->getLocale();
|
||||
|
@@ -87,7 +87,7 @@ class IndexController extends Controller
|
||||
$collection = $this->piggyRepos->getPiggyBanks();
|
||||
$accounts = [];
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
|
||||
// transform piggies using the transformer:
|
||||
$parameters = new ParameterBag();
|
||||
|
@@ -71,7 +71,7 @@ class ShowController extends Controller
|
||||
public function show(PiggyBank $piggyBank)
|
||||
{
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
// transform piggies using the transformer:
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('end', $end);
|
||||
|
@@ -96,9 +96,7 @@ class PreferencesController extends Controller
|
||||
ksort($groupedAccounts);
|
||||
|
||||
$accountIds = $accounts->pluck('id')->toArray();
|
||||
$viewRangePref = app('preferences')->get('viewRange', '1M');
|
||||
|
||||
$viewRange = $viewRangePref->data;
|
||||
$viewRange = app('navigation')->getViewRange(false);
|
||||
$frontPageAccounts = app('preferences')->get('frontPageAccounts', $accountIds);
|
||||
$language = app('steam')->getLanguage();
|
||||
$languages = config('firefly.languages');
|
||||
|
@@ -68,7 +68,7 @@ class TriggerController extends Controller
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($group->transactionJournals as $journal) {
|
||||
Log::debug(sprintf('Set date of journal #%d to today!', $journal->id));
|
||||
$journal->date = Carbon::today();
|
||||
$journal->date = today(config('app.timezone'));
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
|
@@ -118,8 +118,8 @@ class SelectController extends Controller
|
||||
return redirect(route('rules.index'));
|
||||
}
|
||||
// does the user have shared accounts?
|
||||
$first = session('first', Carbon::now()->subYear())->format('Y-m-d');
|
||||
$today = Carbon::now()->format('Y-m-d');
|
||||
$first = session('first', today(config('app.timezone'))->subYear())->format('Y-m-d');
|
||||
$today = today(config('app.timezone'))->format('Y-m-d');
|
||||
$subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
|
||||
|
||||
return view('rules.rule.select-transactions', compact('first', 'today', 'rule', 'subTitle'));
|
||||
|
@@ -110,7 +110,7 @@ class ExecutionController extends Controller
|
||||
public function selectTransactions(RuleGroup $ruleGroup)
|
||||
{
|
||||
$first = session('first')->format('Y-m-d');
|
||||
$today = Carbon::now()->format('Y-m-d');
|
||||
$today = today(config('app.timezone'))->format('Y-m-d');
|
||||
$subTitle = (string)trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]);
|
||||
|
||||
return view('rules.rule-group.select-transactions', compact('first', 'today', 'ruleGroup', 'subTitle'));
|
||||
|
@@ -106,7 +106,11 @@ class SearchController extends Controller
|
||||
*/
|
||||
public function search(Request $request, SearchInterface $searcher): JsonResponse
|
||||
{
|
||||
$fullQuery = (string)$request->get('query');
|
||||
$entry = $request->get('query');
|
||||
if (!is_scalar($entry)) {
|
||||
$entry = '';
|
||||
}
|
||||
$fullQuery = (string)$entry;
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
|
||||
$searcher->parseQuery($fullQuery);
|
||||
|
@@ -85,7 +85,6 @@ class InstallController extends Controller
|
||||
'firefly-iii:migrate-tag-locations' => [],
|
||||
'firefly-iii:migrate-recurrence-type' => [],
|
||||
'firefly-iii:upgrade-liabilities' => [],
|
||||
'firefly-iii:create-group-memberships' => [],
|
||||
'firefly-iii:liabilities-600' => [],
|
||||
|
||||
// verify commands
|
||||
@@ -111,9 +110,10 @@ class InstallController extends Controller
|
||||
'firefly-iii:fix-transaction-types' => [],
|
||||
'firefly-iii:fix-frontpage-accounts' => [],
|
||||
'firefly-iii:fix-ibans' => [],
|
||||
'firefly-iii:create-group-memberships' => [],
|
||||
'firefly-iii:upgrade-group-information' => [],
|
||||
|
||||
// final command to set latest version in DB
|
||||
// final command to set the latest version in DB
|
||||
'firefly-iii:set-latest-version' => ['--james-is-cool' => true],
|
||||
'firefly-iii:verify-security-alerts' => [],
|
||||
];
|
||||
|
@@ -104,6 +104,7 @@ class DeleteController extends Controller
|
||||
*/
|
||||
public function destroy(TransactionGroup $group): RedirectResponse
|
||||
{
|
||||
Log::debug(sprintf('Now in %s(#%d).', __METHOD__, $group->id));
|
||||
if (!$this->isEditableGroup($group)) {
|
||||
return $this->redirectGroupToAccount($group);
|
||||
}
|
||||
|
@@ -98,17 +98,23 @@ class MassController extends Controller
|
||||
*/
|
||||
public function destroy(MassDeleteJournalRequest $request)
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$ids = $request->get('confirm_mass_delete');
|
||||
$count = 0;
|
||||
if (is_array($ids)) {
|
||||
Log::debug('Array of IDs', $ids);
|
||||
/** @var string $journalId */
|
||||
foreach ($ids as $journalId) {
|
||||
Log::debug(sprintf('Searching for ID #%d', $journalId));
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $this->repository->find((int)$journalId);
|
||||
if (null !== $journal && (int)$journalId === $journal->id) {
|
||||
if (null !== $journal && (int)$journalId === (int) $journal->id) {
|
||||
$this->repository->destroyJournal($journal);
|
||||
++$count;
|
||||
Log::debug(sprintf('Deleted transaction journal #%d', $journalId));
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Could not find transaction journal #%d', $journalId));
|
||||
}
|
||||
}
|
||||
app('preferences')->mark();
|
||||
|
@@ -106,7 +106,7 @@ class Range
|
||||
setlocale(LC_TIME, $localeArray);
|
||||
$moneyResult = setlocale(LC_MONETARY, $localeArray);
|
||||
|
||||
// send error to view if could not set money format
|
||||
// send error to view, if could not set money format
|
||||
if (false === $moneyResult) {
|
||||
Log::error('Could not set locale. The following array doesnt work: ', $localeArray);
|
||||
app('view')->share('invalidMonetaryLocale', true);
|
||||
|
@@ -25,11 +25,14 @@ namespace FireflyIII\Http\Requests;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Location;
|
||||
use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Support\Request\AppendsLocationData;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class AccountFormRequest.
|
||||
@@ -39,6 +42,7 @@ class AccountFormRequest extends FormRequest
|
||||
use ConvertsDataTypes;
|
||||
use AppendsLocationData;
|
||||
use ChecksLogin;
|
||||
use ValidatesAdministrationAccess;
|
||||
|
||||
/**
|
||||
* Get all data.
|
||||
@@ -48,6 +52,7 @@ class AccountFormRequest extends FormRequest
|
||||
public function getAccountData(): array
|
||||
{
|
||||
$data = [
|
||||
'administration_id' => $this->convertInteger('administration_id'),
|
||||
'name' => $this->convertString('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'account_type_name' => $this->convertString('objectType'),
|
||||
@@ -67,6 +72,9 @@ class AccountFormRequest extends FormRequest
|
||||
'include_net_worth' => '1',
|
||||
'liability_direction' => $this->convertString('liability_direction'),
|
||||
];
|
||||
if (0 === $data['administration_id']) {
|
||||
$data['administration_id'] = auth()->user()->getAdministrationId();
|
||||
}
|
||||
|
||||
$data = $this->appendLocationData($data, 'location');
|
||||
if (false === $this->boolean('include_net_worth')) {
|
||||
@@ -101,6 +109,7 @@ class AccountFormRequest extends FormRequest
|
||||
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
||||
$rules = [
|
||||
'administration_id' => 'min:1|max:16777216|numeric',
|
||||
'name' => 'required|min:1|uniqueAccountForUser',
|
||||
'opening_balance' => 'numeric|nullable|max:1000000000',
|
||||
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
||||
@@ -130,4 +139,20 @@ class AccountFormRequest extends FormRequest
|
||||
|
||||
return $rules;
|
||||
}
|
||||
/**
|
||||
* Configure the validator instance with special rules for after the basic validation rules.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(
|
||||
function (Validator $validator) {
|
||||
// validate if the account can access this administration
|
||||
$this->validateAdministration($validator, [UserRole::CHANGE_TRANSACTIONS]);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -194,7 +194,7 @@ class RecurrenceFormRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
$today = today(config('app.timezone'));
|
||||
$tomorrow = Carbon::now()->addDay();
|
||||
$tomorrow = today(config('app.timezone'))->addDay();
|
||||
$rules = [
|
||||
// mandatory info for recurrence.
|
||||
'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title',
|
||||
|
@@ -215,7 +215,12 @@ class ReportFormRequest extends FormRequest
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
$set = $this->get('tag');
|
||||
$collection = new Collection();
|
||||
Log::debug('Set is:', $set ?? []);
|
||||
if (is_array($set)) {
|
||||
Log::debug('Set is:', $set);
|
||||
}
|
||||
if (!is_array($set)) {
|
||||
Log::error(sprintf('Set is not an array! "%s"', $set));
|
||||
}
|
||||
if (is_array($set)) {
|
||||
foreach ($set as $tagTag) {
|
||||
Log::debug(sprintf('Now searching for "%s"', $tagTag));
|
||||
|
@@ -47,7 +47,7 @@ class SelectTransactionsRequest extends FormRequest
|
||||
/** @var Carbon $sessionFirst */
|
||||
$sessionFirst = clone session('first');
|
||||
$first = $sessionFirst->subDay()->format('Y-m-d');
|
||||
$today = Carbon::now()->addDay()->format('Y-m-d');
|
||||
$today = today(config('app.timezone'))->addDay()->format('Y-m-d');
|
||||
|
||||
return [
|
||||
'start' => 'required|date|after:'.$first,
|
||||
|
@@ -297,7 +297,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
|
||||
Log::info(sprintf('The amount left is negative, so it will be reset to %s.', $totalAmount));
|
||||
}
|
||||
if (1 !== bccomp('0', $budgetLeft)) {
|
||||
$totalAmount = bcadd($budgetLeft, $budgetLimit->amount);
|
||||
$totalAmount = bcadd($budgetLeft, $totalAmount);
|
||||
Log::info(sprintf('The amount left is positive, so the new amount will be %s.', $totalAmount));
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
@@ -94,18 +95,22 @@ class TransactionGroup extends Model
|
||||
*/
|
||||
public static function routeBinder(string $value): TransactionGroup
|
||||
{
|
||||
Log::debug(sprintf('Now in %s("%s")', __METHOD__, $value));
|
||||
if (auth()->check()) {
|
||||
$groupId = (int)$value;
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
Log::debug(sprintf('User authenticated as %s', $user->email));
|
||||
/** @var TransactionGroup $group */
|
||||
$group = $user->transactionGroups()
|
||||
->with(['transactionJournals', 'transactionJournals.transactions'])
|
||||
->where('transaction_groups.id', $groupId)->first(['transaction_groups.*']);
|
||||
if (null !== $group) {
|
||||
Log::debug(sprintf('Found group #%d.', $group->id));
|
||||
return $group;
|
||||
}
|
||||
}
|
||||
Log::debug('Found no group.');
|
||||
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
@@ -48,6 +48,7 @@ trait CreatesObjectGroups
|
||||
*/
|
||||
protected function findOrCreateObjectGroup(string $title): ?ObjectGroup
|
||||
{
|
||||
$title = substr($title, 0, 255);
|
||||
$maxOrder = $this->getObjectGroupMaxOrder();
|
||||
if (!$this->hasObjectGroup($title)) {
|
||||
return ObjectGroup::create(
|
||||
|
@@ -357,7 +357,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return $savePerMonth;
|
||||
}
|
||||
if (null !== $piggyBank->targetdate && $repetition->currentamount < $piggyBank->targetamount) {
|
||||
$now = Carbon::now();
|
||||
$now = today(config('app.timezone'));
|
||||
$startDate = null !== $piggyBank->startdate && $piggyBank->startdate->gte($now) ? $piggyBank->startdate : $now;
|
||||
$diffInMonths = $startDate->diffInMonths($piggyBank->targetdate, false);
|
||||
$remainingAmount = bcsub($piggyBank->targetamount, $repetition->currentamount);
|
||||
|
@@ -534,7 +534,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
if ('yearly' === $repetition->repetition_type) {
|
||||
//
|
||||
$today = Carbon::now()->endOfYear();
|
||||
$today = today(config('app.timezone'))->endOfYear();
|
||||
$repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment);
|
||||
$diffInYears = $today->diffInYears($repDate);
|
||||
$repDate->addYears($diffInYears); // technically not necessary.
|
||||
|
@@ -426,7 +426,7 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
$stopProcessing = $trigger['stop_processing'] ?? false;
|
||||
$active = $trigger['active'] ?? true;
|
||||
$type = $trigger['type'];
|
||||
if (true === $trigger['prohibited']) {
|
||||
if (true === ($trigger['prohibited'] ?? false) && !str_starts_with($type, '-')) {
|
||||
$type = sprintf('-%s', $type);
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@ use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\GroupMembership;
|
||||
use FireflyIII\Models\InvitedUser;
|
||||
use FireflyIII\Models\Role;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
@@ -281,7 +282,7 @@ class UserRepository implements UserRepositoryInterface
|
||||
*/
|
||||
public function inviteUser(User $user, string $email): InvitedUser
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$now = today(config('app.timezone'));
|
||||
$now->addDays(2);
|
||||
$invitee = new InvitedUser();
|
||||
$invitee->user()->associate($user);
|
||||
@@ -462,8 +463,29 @@ class UserRepository implements UserRepositoryInterface
|
||||
*/
|
||||
public function validateInviteCode(string $code): bool
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$now = today(config('app.timezone'));
|
||||
$invitee = InvitedUser::where('invite_code', $code)->where('expires', '>', $now->format('Y-m-d H:i:s'))->where('redeemed', 0)->first();
|
||||
return null !== $invitee;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getRolesInGroup(User $user, int $groupId): array
|
||||
{
|
||||
/** @var UserGroup $group */
|
||||
$group = UserGroup::find($groupId);
|
||||
if (null === $group) {
|
||||
throw new FireflyException(sprintf('Could not find group #%d', $groupId));
|
||||
}
|
||||
$memberships = $group->groupMemberships()->where('user_id', $user->id)->get();
|
||||
$roles = [];
|
||||
/** @var GroupMembership $membership */
|
||||
foreach ($memberships as $membership) {
|
||||
$role = $membership->userRole;
|
||||
$roles[] = $role->title;
|
||||
}
|
||||
return $roles;
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,13 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function all(): Collection;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param int $groupId
|
||||
* @return array
|
||||
*/
|
||||
public function getRolesInGroup(User $user, int $groupId): array;
|
||||
|
||||
/**
|
||||
* Gives a user a role.
|
||||
*
|
||||
|
@@ -112,7 +112,7 @@ class IsValidAttachmentModel implements Rule
|
||||
TransactionJournal::class => 'validateJournal',
|
||||
];
|
||||
if (!array_key_exists($this->model, $methods)) {
|
||||
Log::error(sprintf('Cannot validate model "%s" in %s.', $this->model, __METHOD__));
|
||||
Log::error(sprintf('Cannot validate model "%s" in %s.', substr($this->model, 0, 20), __METHOD__));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -74,7 +74,7 @@ class UpdateRequest implements UpdateRequestInterface
|
||||
// always fall back to current version:
|
||||
$return = [
|
||||
'version' => config('firefly.version'),
|
||||
'date' => Carbon::today()->startOfDay(),
|
||||
'date' => today(config('app.timezone'))->startOfDay(),
|
||||
'level' => 'error',
|
||||
'message' => (string)trans('firefly.unknown_error'),
|
||||
];
|
||||
@@ -171,7 +171,7 @@ class UpdateRequest implements UpdateRequestInterface
|
||||
// a newer version is available!
|
||||
/** @var Carbon $released */
|
||||
$released = $information['date'];
|
||||
$today = Carbon::today()->startOfDay();
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
$diff = $today->diffInDays($released);
|
||||
$expectedDiff = config('firefly.update_minimum_age') ?? 6;
|
||||
// it's still very fresh, and user wants a stable release:
|
||||
|
@@ -46,5 +46,8 @@ class CategoryDestroyService
|
||||
|
||||
// also delete all relations between categories and transactions:
|
||||
DB::table('category_transaction')->where('category_id', (int)$category->id)->delete();
|
||||
|
||||
// delete references to category from recurring transactions.
|
||||
DB::table('rt_meta')->where('name', 'category_id')->where('value', $category->id)->delete();
|
||||
}
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ trait JournalServiceTrait
|
||||
|
||||
// if result is NULL but IBAN is set, any result of the search by NAME can't overrule
|
||||
// this account. In such a case, the name search must be retried with a new name.
|
||||
if (null !== $result && null === $numberResult && null === $ibanResult && null !== $data['iban']) {
|
||||
if (null !== $result && null === $numberResult && null === $ibanResult && '' !== (string) $data['iban']) {
|
||||
$data['name'] = sprintf('%s (%s)', $data['name'], $data['iban']);
|
||||
Log::debug(sprintf('Search again using the new name, "%s".', $data['name']));
|
||||
$result = $this->findAccountByName(null, $data, $expectedTypes[$transactionType]);
|
||||
|
@@ -294,7 +294,7 @@ trait RecurringTransactionTrait
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$transaction->recurrenceTransactionMeta()->where('name', 'category_name')->delete();
|
||||
$meta = $transaction->recurrenceTransactionMeta()->where('name', 'category_id')->first();
|
||||
if (null === $meta) {
|
||||
$meta = new RecurrenceTransactionMeta();
|
||||
|
@@ -65,7 +65,7 @@ class GroupCloneService
|
||||
{
|
||||
$newJournal = $journal->replicate();
|
||||
$newJournal->transaction_group_id = $newGroup->id;
|
||||
$newJournal->date = Carbon::now();
|
||||
$newJournal->date = today(config('app.timezone'));
|
||||
$newJournal->save();
|
||||
|
||||
foreach ($journal->transactions as $transaction) {
|
||||
|
@@ -224,9 +224,10 @@ class RecurrenceUpdateService
|
||||
*/
|
||||
private function updateTransactions(Recurrence $recurrence, array $transactions): void
|
||||
{
|
||||
Log::debug('Now in updateTransactions()');
|
||||
$originalCount = $recurrence->recurrenceTransactions()->count();
|
||||
if (0 === count($transactions)) {
|
||||
// wont drop transactions, rather avoid.
|
||||
// won't drop transactions, rather avoid.
|
||||
return;
|
||||
}
|
||||
// user added or removed repetitions, delete all and recreate:
|
||||
@@ -240,12 +241,13 @@ class RecurrenceUpdateService
|
||||
$currencyFactory = app(TransactionCurrencyFactory::class);
|
||||
// loop all and try to match them:
|
||||
if ($originalCount === count($transactions)) {
|
||||
Log::debug('Loop and find');
|
||||
Log::debug(sprintf('Count is equal (%d), update transactions.', $originalCount));
|
||||
foreach ($transactions as $current) {
|
||||
$match = $this->matchTransaction($recurrence, $current);
|
||||
if (null === $match) {
|
||||
throw new FireflyException('Cannot match recurring transaction to existing transaction. Not sure what to do. Break.');
|
||||
}
|
||||
// complex loop to find currency:
|
||||
$currency = null;
|
||||
$foreignCurrency = null;
|
||||
if (array_key_exists('currency_id', $current) || array_key_exists('currency_code', $current)) {
|
||||
@@ -267,7 +269,7 @@ class RecurrenceUpdateService
|
||||
$current['foreign_currency_id'] = (int)$foreignCurrency->id;
|
||||
}
|
||||
|
||||
// update fields
|
||||
// update fields that are part of the recurring transaction itself.
|
||||
$fields = [
|
||||
'source_id' => 'source_id',
|
||||
'destination_id' => 'destination_id',
|
||||
@@ -293,11 +295,13 @@ class RecurrenceUpdateService
|
||||
// reset category if name is set but empty:
|
||||
// can be removed when v1 is retired.
|
||||
if (array_key_exists('category_name', $current) && '' === (string)$current['category_name']) {
|
||||
Log::debug('Category name is submitted but is empty. Set category to be empty.');
|
||||
$current['category_name'] = null;
|
||||
$current['category_id'] = 0;
|
||||
}
|
||||
|
||||
if (array_key_exists('category_id', $current)) {
|
||||
Log::debug(sprintf('Category ID is submitted, set category to be %d.', (int)$current['category_id']));
|
||||
$this->setCategory($match, (int)$current['category_id']);
|
||||
}
|
||||
|
||||
@@ -319,9 +323,10 @@ class RecurrenceUpdateService
|
||||
*/
|
||||
private function matchTransaction(Recurrence $recurrence, array $data): ?RecurrenceTransaction
|
||||
{
|
||||
Log::debug('Now in matchTransaction()');
|
||||
$originalCount = $recurrence->recurrenceTransactions()->count();
|
||||
if (1 === $originalCount) {
|
||||
Log::debug('Return the first one');
|
||||
Log::debug('Return the first one.');
|
||||
|
||||
return $recurrence->recurrenceTransactions()->first();
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
{
|
||||
// have the signature generator generate a signature. If it fails, the error thrown will
|
||||
// end up in send() to be caught.
|
||||
$signatureGenerator = app(SignatureGeneratorInterface::class);
|
||||
$signatureGenerator = app(SignatureGeneratorInterface::class);
|
||||
$this->message->sent = true;
|
||||
$this->message->save();
|
||||
try {
|
||||
@@ -109,7 +109,7 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
];
|
||||
$client = new Client();
|
||||
try {
|
||||
$res = $client->request('POST', $this->message->webhook->url, $options);
|
||||
$res = $client->request('POST', $this->message->webhook->url, $options);
|
||||
} catch (RequestException|ConnectException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
@@ -122,8 +122,11 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
|
||||
$attempt = new WebhookAttempt();
|
||||
$attempt->webhookMessage()->associate($this->message);
|
||||
$attempt->status_code = $e->hasResponse() ? $e->getResponse()->getStatusCode() : 0;
|
||||
$attempt->logs = $logs;
|
||||
$attempt->status_code = 0;
|
||||
if (method_exists($e, 'hasResponse') && method_exists($e, 'getResponse')) {
|
||||
$attempt->status_code = $e->hasResponse() ? $e->getResponse()->getStatusCode() : 0;
|
||||
}
|
||||
$attempt->logs = $logs;
|
||||
$attempt->save();
|
||||
|
||||
return;
|
||||
|
@@ -52,7 +52,7 @@ class RemoteUserGuard implements Guard
|
||||
{
|
||||
/** @var Request $request */
|
||||
$request = $app->get('request');
|
||||
Log::debug(sprintf('Created RemoteUserGuard for "%s"', $request?->getRequestUri()));
|
||||
Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
|
||||
$this->application = $app;
|
||||
$this->provider = $provider;
|
||||
$this->user = null;
|
||||
@@ -82,16 +82,18 @@ class RemoteUserGuard implements Guard
|
||||
$header = config('auth.guard_header', 'REMOTE_USER');
|
||||
$userID = request()->server($header) ?? null;
|
||||
|
||||
//$userID = 'james@firefly';
|
||||
|
||||
if (function_exists('apache_request_headers')) {
|
||||
Log::debug('Use apache_request_headers to find user ID.');
|
||||
$userID = request()->server($header) ?? apache_request_headers()[$header] ?? null;
|
||||
}
|
||||
if (null === $userID) {
|
||||
|
||||
if (null === $userID || '' === $userID) {
|
||||
Log::error(sprintf('No user in header "%s".', $header));
|
||||
throw new FireflyException('The guard header was unexpectedly empty. See the logs.');
|
||||
}
|
||||
|
||||
Log::debug(sprintf('User ID found in header is "%s"', $userID));
|
||||
|
||||
/** @var User $retrievedUser */
|
||||
$retrievedUser = $this->provider->retrieveById($userID);
|
||||
|
||||
@@ -139,8 +141,13 @@ class RemoteUserGuard implements Guard
|
||||
public function user(): ?User
|
||||
{
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
//$this->authenticate();
|
||||
return $this->user;
|
||||
$user = $this->user;
|
||||
if (null === $user) {
|
||||
Log::debug('User is NULL');
|
||||
return null;
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -48,20 +48,20 @@ class Date implements BinderInterface
|
||||
$fiscalHelper = app(FiscalHelperInterface::class);
|
||||
|
||||
$magicWords = [
|
||||
'currentMonthStart' => Carbon::now()->startOfMonth(),
|
||||
'currentMonthEnd' => Carbon::now()->endOfMonth(),
|
||||
'currentYearStart' => Carbon::now()->startOfYear(),
|
||||
'currentYearEnd' => Carbon::now()->endOfYear(),
|
||||
'currentMonthStart' => today(config('app.timezone'))->startOfMonth(),
|
||||
'currentMonthEnd' => today(config('app.timezone'))->endOfMonth(),
|
||||
'currentYearStart' => today(config('app.timezone'))->startOfYear(),
|
||||
'currentYearEnd' => today(config('app.timezone'))->endOfYear(),
|
||||
|
||||
'previousMonthStart' => Carbon::now()->startOfMonth()->subDay()->startOfMonth(),
|
||||
'previousMonthEnd' => Carbon::now()->startOfMonth()->subDay()->endOfMonth(),
|
||||
'previousYearStart' => Carbon::now()->startOfYear()->subDay()->startOfYear(),
|
||||
'previousYearEnd' => Carbon::now()->startOfYear()->subDay()->endOfYear(),
|
||||
'previousMonthStart' => today(config('app.timezone'))->startOfMonth()->subDay()->startOfMonth(),
|
||||
'previousMonthEnd' => today(config('app.timezone'))->startOfMonth()->subDay()->endOfMonth(),
|
||||
'previousYearStart' => today(config('app.timezone'))->startOfYear()->subDay()->startOfYear(),
|
||||
'previousYearEnd' => today(config('app.timezone'))->startOfYear()->subDay()->endOfYear(),
|
||||
|
||||
'currentFiscalYearStart' => $fiscalHelper->startOfFiscalYear(Carbon::now()),
|
||||
'currentFiscalYearEnd' => $fiscalHelper->endOfFiscalYear(Carbon::now()),
|
||||
'previousFiscalYearStart' => $fiscalHelper->startOfFiscalYear(Carbon::now())->subYear(),
|
||||
'previousFiscalYearEnd' => $fiscalHelper->endOfFiscalYear(Carbon::now())->subYear(),
|
||||
'currentFiscalYearStart' => $fiscalHelper->startOfFiscalYear(today(config('app.timezone'))),
|
||||
'currentFiscalYearEnd' => $fiscalHelper->endOfFiscalYear(today(config('app.timezone'))),
|
||||
'previousFiscalYearStart' => $fiscalHelper->startOfFiscalYear(today(config('app.timezone')))->subYear(),
|
||||
'previousFiscalYearEnd' => $fiscalHelper->endOfFiscalYear(today(config('app.timezone')))->subYear(),
|
||||
];
|
||||
if (array_key_exists($value, $magicWords)) {
|
||||
$return = $magicWords[$value];
|
||||
|
@@ -43,7 +43,7 @@ class AutoBudgetCronjob extends AbstractCronjob
|
||||
$config = app('fireflyconfig')->get('last_ab_job', 0);
|
||||
$lastTime = (int)$config->data;
|
||||
$diff = time() - $lastTime;
|
||||
$diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
if (0 === $lastTime) {
|
||||
Log::info('Auto budget cron-job has never fired before.');
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ class BillWarningCronjob extends AbstractCronjob
|
||||
$config = app('fireflyconfig')->get('last_bw_job', 0);
|
||||
$lastTime = (int)$config->data;
|
||||
$diff = time() - $lastTime;
|
||||
$diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
|
||||
if (0 === $lastTime) {
|
||||
Log::info('The bill warning cron-job has never fired before.');
|
||||
|
@@ -43,7 +43,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
|
||||
$config = app('fireflyconfig')->get('last_cer_job', 0);
|
||||
$lastTime = (int)$config->data;
|
||||
$diff = time() - $lastTime;
|
||||
$diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
if (0 === $lastTime) {
|
||||
Log::info('Exchange rates cron-job has never fired before.');
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ class RecurringCronjob extends AbstractCronjob
|
||||
$config = app('fireflyconfig')->get('last_rt_job', 0);
|
||||
$lastTime = (int)$config->data;
|
||||
$diff = time() - $lastTime;
|
||||
$diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
|
||||
if (0 === $lastTime) {
|
||||
Log::info('Recurring transactions cron-job has never fired before.');
|
||||
|
@@ -158,7 +158,7 @@ trait ConvertsExchangeRates
|
||||
private function convertAmount(string $amount, TransactionCurrency $from, TransactionCurrency $to, ?Carbon $date = null): string
|
||||
{
|
||||
Log::debug(sprintf('Converting %s from %s to %s', $amount, $from->code, $to->code));
|
||||
$date = $date ?? Carbon::now();
|
||||
$date = $date ?? today(config('app.timezone'));
|
||||
$rate = $this->getRate($from, $to, $date);
|
||||
|
||||
return bcmul($amount, $rate);
|
||||
|
@@ -45,7 +45,7 @@ trait DateCalculation
|
||||
public function activeDaysLeft(Carbon $start, Carbon $end): int
|
||||
{
|
||||
$difference = $start->diffInDays($end) + 1;
|
||||
$today = Carbon::now()->startOfDay();
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
|
||||
if ($start->lte($today) && $end->gte($today)) {
|
||||
$difference = $today->diffInDays($end);
|
||||
@@ -67,7 +67,7 @@ trait DateCalculation
|
||||
protected function activeDaysPassed(Carbon $start, Carbon $end): int
|
||||
{
|
||||
$difference = $start->diffInDays($end) + 1;
|
||||
$today = Carbon::now()->startOfDay();
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
|
||||
if ($start->lte($today) && $end->gte($today)) {
|
||||
$difference = $start->diffInDays($today) + 1;
|
||||
|
@@ -95,7 +95,7 @@ trait GetConfigurationData
|
||||
*/
|
||||
protected function getDateRangeConfig(): array // get configuration + get preferences.
|
||||
{
|
||||
$viewRange = (string)app('preferences')->get('viewRange', '1M')->data;
|
||||
$viewRange = app('navigation')->getViewRange(false);
|
||||
/** @var Carbon $start */
|
||||
$start = session('start');
|
||||
/** @var Carbon $end */
|
||||
@@ -117,18 +117,20 @@ trait GetConfigurationData
|
||||
$customPeriodEnd = app('navigation')->endOfPeriod($customPeriodStart, $viewRange);
|
||||
$ranges[$index] = [$customPeriodStart, $customPeriodEnd];
|
||||
}
|
||||
// then add previous range and next range
|
||||
$previousDate = app('navigation')->subtractPeriod($start, $viewRange);
|
||||
$index = app('navigation')->periodShow($previousDate, $viewRange);
|
||||
$previousStart = app('navigation')->startOfPeriod($previousDate, $viewRange);
|
||||
$previousEnd = app('navigation')->endOfPeriod($previousStart, $viewRange);
|
||||
$ranges[$index] = [$previousStart, $previousEnd];
|
||||
// then add previous range and next range, but skip this for the lastX and YTD stuff.
|
||||
if (!in_array($viewRange, config('firefly.dynamic_date_ranges', []), true)) {
|
||||
$previousDate = app('navigation')->subtractPeriod($start, $viewRange);
|
||||
$index = app('navigation')->periodShow($previousDate, $viewRange);
|
||||
$previousStart = app('navigation')->startOfPeriod($previousDate, $viewRange);
|
||||
$previousEnd = app('navigation')->endOfPeriod($previousStart, $viewRange);
|
||||
$ranges[$index] = [$previousStart, $previousEnd];
|
||||
|
||||
$nextDate = app('navigation')->addPeriod($start, $viewRange, 0);
|
||||
$index = app('navigation')->periodShow($nextDate, $viewRange);
|
||||
$nextStart = app('navigation')->startOfPeriod($nextDate, $viewRange);
|
||||
$nextEnd = app('navigation')->endOfPeriod($nextStart, $viewRange);
|
||||
$ranges[$index] = [$nextStart, $nextEnd];
|
||||
$nextDate = app('navigation')->addPeriod($start, $viewRange, 0);
|
||||
$index = app('navigation')->periodShow($nextDate, $viewRange);
|
||||
$nextStart = app('navigation')->startOfPeriod($nextDate, $viewRange);
|
||||
$nextEnd = app('navigation')->endOfPeriod($nextStart, $viewRange);
|
||||
$ranges[$index] = [$nextStart, $nextEnd];
|
||||
}
|
||||
|
||||
// today:
|
||||
/** @var Carbon $todayStart */
|
||||
@@ -140,22 +142,22 @@ trait GetConfigurationData
|
||||
}
|
||||
|
||||
// last seven days:
|
||||
$seven = Carbon::now()->subDays(7);
|
||||
$seven = today(config('app.timezone'))->subDays(7);
|
||||
$index = (string)trans('firefly.last_seven_days');
|
||||
$ranges[$index] = [$seven, new Carbon()];
|
||||
|
||||
// last 30 days:
|
||||
$thirty = Carbon::now()->subDays(30);
|
||||
$thirty = today(config('app.timezone'))->subDays(30);
|
||||
$index = (string)trans('firefly.last_thirty_days');
|
||||
$ranges[$index] = [$thirty, new Carbon()];
|
||||
|
||||
// month to date:
|
||||
$monthBegin = Carbon::now()->startOfMonth();
|
||||
$monthBegin = today(config('app.timezone'))->startOfMonth();
|
||||
$index = (string)trans('firefly.month_to_date');
|
||||
$ranges[$index] = [$monthBegin, new Carbon()];
|
||||
|
||||
// year to date:
|
||||
$yearBegin = Carbon::now()->startOfYear();
|
||||
$yearBegin = today(config('app.timezone'))->startOfYear();
|
||||
$index = (string)trans('firefly.year_to_date');
|
||||
$ranges[$index] = [$yearBegin, new Carbon()];
|
||||
|
||||
|
@@ -85,7 +85,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for cache
|
||||
@@ -95,7 +95,7 @@ trait PeriodOverview
|
||||
$cache->addProperty('account-show-period-entries');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
// return $cache->get();
|
||||
return $cache->get();
|
||||
}
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
@@ -276,7 +276,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for entries with their amounts.
|
||||
@@ -356,7 +356,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
@@ -412,7 +412,7 @@ trait PeriodOverview
|
||||
protected function getNoCategoryPeriodOverview(Carbon $theDate): array
|
||||
{
|
||||
Log::debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon() : $first->date;
|
||||
$end = clone $theDate;
|
||||
@@ -483,7 +483,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for cache
|
||||
@@ -558,7 +558,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
|
@@ -145,9 +145,9 @@ trait RequestInformation
|
||||
final protected function notInSessionRange(Carbon $date): bool // Validate a preference
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = session('end', Carbon::now()->endOfMonth());
|
||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$result = false;
|
||||
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
@@ -175,7 +175,7 @@ trait RequestInformation
|
||||
$attributes['startDate'] = Carbon::createFromFormat('Ymd', $attributes['startDate'])->startOfDay();
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::debug(sprintf('Not important error message: %s', $e->getMessage()));
|
||||
$date = Carbon::now()->startOfMonth();
|
||||
$date = today(config('app.timezone'))->startOfMonth();
|
||||
$attributes['startDate'] = $date;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ trait RequestInformation
|
||||
$attributes['endDate'] = Carbon::createFromFormat('Ymd', $attributes['endDate'])->endOfDay();
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::debug(sprintf('Not important error message: %s', $e->getMessage()));
|
||||
$date = Carbon::now()->startOfMonth();
|
||||
$date = today(config('app.timezone'))->startOfMonth();
|
||||
$attributes['endDate'] = $date;
|
||||
}
|
||||
|
||||
|
@@ -255,9 +255,9 @@ class Navigation
|
||||
// and end added to $theCurrentEnd
|
||||
if ('custom' === $repeatFreq) {
|
||||
/** @var Carbon $tStart */
|
||||
$tStart = session('start', Carbon::now()->startOfMonth());
|
||||
$tStart = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $tEnd */
|
||||
$tEnd = session('end', Carbon::now()->endOfMonth());
|
||||
$tEnd = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$diffInDays = $tStart->diffInDays($tEnd);
|
||||
$currentEnd->addDays($diffInDays);
|
||||
|
||||
@@ -428,6 +428,35 @@ class Navigation
|
||||
return $date->format('Y-m-d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's view range and if necessary, corrects the dynamic view
|
||||
* range to a normal range.
|
||||
* @param bool $correct
|
||||
* @return string
|
||||
*/
|
||||
public function getViewRange(bool $correct): string
|
||||
{
|
||||
$range = (string)app('preferences')->get('viewRange', '1M')?->data ?? '1M';
|
||||
if (!$correct) {
|
||||
return $range;
|
||||
}
|
||||
switch ($range) {
|
||||
default:
|
||||
return $range;
|
||||
case 'last7':
|
||||
return '1W';
|
||||
case 'last30':
|
||||
case 'MTD':
|
||||
return '1M';
|
||||
case 'last90':
|
||||
case 'QTD':
|
||||
return '3M';
|
||||
case 'last365':
|
||||
case 'YTD':
|
||||
return '1Y';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the date difference between start and end is less than a month, method returns trans(config.month_and_day). If the difference is less than a year,
|
||||
* method returns "config.month". If the date difference is larger, method returns "config.year".
|
||||
@@ -573,9 +602,9 @@ class Navigation
|
||||
// this is then subtracted from $theDate (* $subtract).
|
||||
if ('custom' === $repeatFreq) {
|
||||
/** @var Carbon $tStart */
|
||||
$tStart = session('start', Carbon::now()->startOfMonth());
|
||||
$tStart = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $tEnd */
|
||||
$tEnd = session('end', Carbon::now()->endOfMonth());
|
||||
$tEnd = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$diffInDays = $tStart->diffInDays($tEnd);
|
||||
$date->subDays($diffInDays * $subtract);
|
||||
|
||||
@@ -621,6 +650,7 @@ class Navigation
|
||||
*/
|
||||
public function updateEndDate(string $range, Carbon $start): Carbon
|
||||
{
|
||||
Log::debug(sprintf('updateEndDate("%s", "%s")', $range, $start->format('Y-m-d')));
|
||||
$functionMap = [
|
||||
'1D' => 'endOfDay',
|
||||
'1W' => 'endOfWeek',
|
||||
@@ -664,6 +694,9 @@ class Navigation
|
||||
'MTD',
|
||||
];
|
||||
if (in_array($range, $list, true)) {
|
||||
$end = today(config('app.timezone'));
|
||||
$end->endOfDay();
|
||||
Log::debug(sprintf('updateEndDate returns "%s"', $end->format('Y-m-d')));
|
||||
return $end;
|
||||
}
|
||||
|
||||
@@ -680,6 +713,7 @@ class Navigation
|
||||
*/
|
||||
public function updateStartDate(string $range, Carbon $start): Carbon
|
||||
{
|
||||
Log::debug(sprintf('updateStartDate("%s", "%s")', $range, $start->format('Y-m-d')));
|
||||
$functionMap = [
|
||||
'1D' => 'startOfDay',
|
||||
'1W' => 'startOfWeek',
|
||||
|
@@ -128,7 +128,7 @@ class ParseDateString
|
||||
*/
|
||||
protected function parseKeyword(string $keyword): Carbon
|
||||
{
|
||||
$today = Carbon::today()->startOfDay();
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
|
||||
return match ($keyword) {
|
||||
default => $today,
|
||||
@@ -164,7 +164,7 @@ class ParseDateString
|
||||
{
|
||||
Log::debug(sprintf('Now in parseRelativeDate("%s")', $date));
|
||||
$parts = explode(' ', $date);
|
||||
$today = Carbon::today()->startOfDay();
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
$functions = [
|
||||
[
|
||||
'd' => 'subDays',
|
||||
|
@@ -46,10 +46,11 @@ trait ConvertsDataTypes
|
||||
* Abstract method that always exists in the Request classes that use this
|
||||
* trait, OR a stub needs to be added by any other class that uses this train.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function has($key);
|
||||
|
||||
/**
|
||||
* Return integer value.
|
||||
*
|
||||
@@ -71,7 +72,11 @@ trait ConvertsDataTypes
|
||||
*/
|
||||
public function convertString(string $field): string
|
||||
{
|
||||
return $this->clearString((string)($this->get($field) ?? ''), false);
|
||||
$entry = $this->get($field);
|
||||
if (!is_scalar($entry)) {
|
||||
return '';
|
||||
}
|
||||
return $this->clearString((string)$entry, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +90,10 @@ trait ConvertsDataTypes
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
$search = [
|
||||
if ('' === $string) {
|
||||
return '';
|
||||
}
|
||||
$search = [
|
||||
"\0", // NUL
|
||||
"\f", // form feed
|
||||
"\v", // vertical tab
|
||||
@@ -135,14 +143,20 @@ trait ConvertsDataTypes
|
||||
"\u{3000}", // ideographic space
|
||||
"\u{FEFF}", // zero width no -break space
|
||||
];
|
||||
$replace = "\x20"; // plain old normal space
|
||||
$string = str_replace($search, $replace, $string);
|
||||
$replace = "\x20"; // plain old normal space
|
||||
$string = str_replace($search, $replace, $string);
|
||||
|
||||
$secondSearch = $keepNewlines ? ["\r"] : ["\r", "\n", "\t", "\036", "\025"];
|
||||
$string = str_replace($secondSearch, '', $string);
|
||||
|
||||
// clear zalgo text (TODO also in API v2)
|
||||
$string = preg_replace('/\pM/u', '', $string);
|
||||
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
if ('' === $string) {
|
||||
return '';
|
||||
}
|
||||
return trim($string);
|
||||
}
|
||||
|
||||
|
@@ -162,7 +162,7 @@ class OperatorQuerySearch implements SearchInterface
|
||||
} catch (TypeError|LogicException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error(sprintf('Could not parse search: "%s".', $query));
|
||||
throw new FireflyException('Invalid search value. See the logs.', 0, $e);
|
||||
throw new FireflyException(sprintf('Invalid search value "%s". See the logs.', e($query)), 0, $e);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Found %d node(s)', count($query1->getNodes())));
|
||||
|
@@ -67,7 +67,7 @@ class General extends AbstractExtension
|
||||
return '0';
|
||||
}
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', Carbon::now()->endOfMonth());
|
||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
|
||||
return app('steam')->balance($account, $date);
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
|
||||
@@ -40,20 +41,22 @@ class UserTransformer extends AbstractTransformer
|
||||
* @param User $user
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function transform(User $user): array
|
||||
{
|
||||
$this->repository = $this->repository ?? app(UserRepositoryInterface::class);
|
||||
|
||||
return [
|
||||
'id' => (int)$user->id,
|
||||
'created_at' => $user->created_at->toAtomString(),
|
||||
'updated_at' => $user->updated_at->toAtomString(),
|
||||
'email' => $user->email,
|
||||
'blocked' => 1 === (int)$user->blocked,
|
||||
'blocked_code' => '' === $user->blocked_code ? null : $user->blocked_code,
|
||||
'role' => $this->repository->getRoleByUser($user),
|
||||
'links' => [
|
||||
'id' => (int)$user->id,
|
||||
'administration_id' => (string)$user->getAdministrationId(),
|
||||
'created_at' => $user->created_at->toAtomString(),
|
||||
'updated_at' => $user->updated_at->toAtomString(),
|
||||
'email' => $user->email,
|
||||
'blocked' => 1 === (int)$user->blocked,
|
||||
'blocked_code' => '' === $user->blocked_code ? null : $user->blocked_code,
|
||||
'role' => $this->repository->getRoleByUser($user),
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
'uri' => '/users/'.$user->id,
|
||||
|
@@ -239,7 +239,7 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
*/
|
||||
private function stringFromArray(NullArrayObject $array, string $key, ?string $default): ?string
|
||||
{
|
||||
Log::debug(sprintf('%s: %s', $key, var_export($array[$key])));
|
||||
//Log::debug(sprintf('%s: %s', $key, var_export($array[$key], true)));
|
||||
if (null === $array[$key] && null === $default) {
|
||||
return null;
|
||||
}
|
||||
|
16
app/User.php
16
app/User.php
@@ -27,6 +27,7 @@ namespace FireflyIII;
|
||||
use Eloquent;
|
||||
use Exception;
|
||||
use FireflyIII\Events\RequestedNewPassword;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
@@ -361,6 +362,21 @@ class User extends Authenticatable
|
||||
return $this->hasMany(GroupMembership::class)->with(['userGroup', 'userRole']);
|
||||
}
|
||||
|
||||
/**
|
||||
* A safe method that returns the user's current administration ID (group ID).
|
||||
*
|
||||
* @return int
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getAdministrationId(): int
|
||||
{
|
||||
$groupId = (int)$this->user_group_id;
|
||||
if (0 === $groupId) {
|
||||
throw new FireflyException('User has no administration ID.');
|
||||
}
|
||||
return $groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Link to object groups.
|
||||
|
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* ValidatesAdministrationAccess.php
|
||||
* Copyright (c) 2023 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Validation\Administration;
|
||||
|
||||
use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Trait ValidatesAdministrationAccess
|
||||
*/
|
||||
trait ValidatesAdministrationAccess
|
||||
{
|
||||
/**
|
||||
* @param Validator $validator
|
||||
* @param array $allowedRoles
|
||||
* @return void
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
protected function validateAdministration(Validator $validator, array $allowedRoles): void
|
||||
{
|
||||
Log::debug('Now in validateAdministration()');
|
||||
if (!auth()->check()) {
|
||||
Log::error('User is not authenticated.');
|
||||
throw new AuthenticationException('No access to validateAdministration() method.');
|
||||
}
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
// get data from request:
|
||||
$data = $validator->getData();
|
||||
// check if user is part of this administration
|
||||
$administrationId = (int)($data['administration_id'] ?? $user->getAdministrationId());
|
||||
// safety catch:
|
||||
if (0 === $administrationId) {
|
||||
Log::error('validateAdministration ran into empty administration ID.');
|
||||
throw new AuthenticationException('Cannot validate administration.');
|
||||
}
|
||||
// grab the group:
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
|
||||
// collect the user's roles in this group:
|
||||
$array = $repository->getRolesInGroup($user, $administrationId);
|
||||
if (0 === count($array)) {
|
||||
Log::error(sprintf('User #%d ("%s") has no membership in group #%d.', $user->id, $user->email, $administrationId));
|
||||
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
|
||||
return;
|
||||
}
|
||||
if (in_array(UserRole::OWNER, $array, true)) {
|
||||
Log::debug('User is owner of this administration.');
|
||||
return;
|
||||
}
|
||||
if (in_array(UserRole::FULL, $array, true)) {
|
||||
Log::debug('User has full access to this administration.');
|
||||
return;
|
||||
}
|
||||
$access = true;
|
||||
foreach ($allowedRoles as $allowedRole) {
|
||||
if (!in_array($allowedRole, $array, true)) {
|
||||
$access = false;
|
||||
}
|
||||
}
|
||||
if (false === $access) {
|
||||
Log::error(
|
||||
sprintf(
|
||||
'User #%d has memberships [%s] to group #%d but needs [%s].',
|
||||
$user->id,
|
||||
join(', ', $array),
|
||||
$administrationId,
|
||||
join(', ', $allowedRoles)
|
||||
)
|
||||
);
|
||||
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user