Compare commits

..

68 Commits

Author SHA1 Message Date
github-actions[bot]
860ae9d931 Merge pull request #11139 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-10-31 06:51:41 +01:00
github-actions[bot]
d045248747 Merge pull request #11138 from firefly-iii/release-1761889889
🤖 Automatically merge the PR into the develop branch.
2025-10-31 06:51:36 +01:00
JC5
87aa6feb29 🤖 Auto commit for release '6.4.3' on 2025-10-31 2025-10-31 06:51:29 +01:00
James Cole
dfa32353da Re-order changelog. 2025-10-31 06:47:30 +01:00
github-actions[bot]
08c9703900 Merge pull request #11137 from firefly-iii/release-1761889447
🤖 Automatically merge the PR into the develop branch.
2025-10-31 06:44:16 +01:00
JC5
101f56d1b1 🤖 Auto commit for release 'develop' on 2025-10-31 2025-10-31 06:44:07 +01:00
James Cole
83bdaff033 Update changelog. 2025-10-31 06:39:28 +01:00
James Cole
e25fbcfb19 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-10-31 06:31:02 +01:00
James Cole
40c4c9f109 Fix #11132 2025-10-31 06:30:56 +01:00
github-actions[bot]
d178956541 Merge pull request #11135 from firefly-iii/release-1761853876
🤖 Automatically merge the PR into the develop branch.
2025-10-30 20:51:23 +01:00
JC5
c29f997733 🤖 Auto commit for release 'develop' on 2025-10-30 2025-10-30 20:51:16 +01:00
James Cole
2aabb56d2d Fix https://github.com/firefly-iii/firefly-iii/issues/11134 2025-10-30 20:46:43 +01:00
github-actions[bot]
e1e18a2a0c Merge pull request #11130 from firefly-iii/release-1761763997
🤖 Automatically merge the PR into the develop branch.
2025-10-29 19:53:25 +01:00
JC5
2c41694f41 🤖 Auto commit for release 'develop' on 2025-10-29 2025-10-29 19:53:18 +01:00
James Cole
48a641286c Fix account type list. 2025-10-29 19:47:35 +01:00
James Cole
5eec91f439 Merge branch 'main' into develop
# Conflicts:
#	package-lock.json
2025-10-29 19:22:19 +01:00
James Cole
782f0c7d54 Update readme. 2025-10-29 17:41:56 +01:00
James Cole
a4dff6d39f Fix #11122 2025-10-27 10:00:16 +01:00
James Cole
9312ddbb7b Reset the anonimity. 2025-10-27 08:51:50 +01:00
github-actions[bot]
14a9bede11 Merge pull request #11121 from firefly-iii/release-1761535923
🤖 Automatically merge the PR into the develop branch.
2025-10-27 04:32:13 +01:00
JC5
58d798df86 🤖 Auto commit for release 'develop' on 2025-10-27 2025-10-27 04:32:03 +01:00
James Cole
e740fc57a6 Replace a few request class calls. 2025-10-26 17:15:54 +01:00
James Cole
ecd7750030 Replace a few request instances. 2025-10-26 16:04:03 +01:00
James Cole
19c4a82194 Use new API request. 2025-10-26 15:37:27 +01:00
James Cole
ffc91d5ead Migrate one of the API endpoints to the new unified API thing. 2025-10-26 12:28:42 +01:00
James Cole
4898c29b85 Replace reference to facade. 2025-10-26 12:12:30 +01:00
github-actions[bot]
84b4ab0cc2 Merge pull request #11112 from firefly-iii/release-1761470095
🤖 Automatically merge the PR into the develop branch.
2025-10-26 10:15:03 +01:00
JC5
eb808a0fbc 🤖 Auto commit for release 'develop' on 2025-10-26 2025-10-26 10:14:55 +01:00
James Cole
d25ae50d30 Fix routes. 2025-10-26 10:09:59 +01:00
github-actions[bot]
c43821e29c Merge pull request #11111 from firefly-iii/release-1761469189
🤖 Automatically merge the PR into the develop branch.
2025-10-26 09:59:56 +01:00
JC5
b7570b2651 🤖 Auto commit for release 'develop' on 2025-10-26 2025-10-26 09:59:49 +01:00
James Cole
cb77609f27 Add disclaimer. 2025-10-26 09:55:51 +01:00
James Cole
99651bb61e Catch some exceptions. 2025-10-26 09:53:19 +01:00
James Cole
bf1e14f66d Explain about user agents. 2025-10-26 09:45:00 +01:00
github-actions[bot]
d0e55804f8 Merge pull request #11110 from firefly-iii/release-1761467960
🤖 Automatically merge the PR into the develop branch.
2025-10-26 09:39:29 +01:00
JC5
0a9715b8c1 🤖 Auto commit for release 'develop' on 2025-10-26 2025-10-26 09:39:20 +01:00
James Cole
61390e67f6 Add debug info. 2025-10-26 09:34:40 +01:00
James Cole
536d25980f Fix issues related to #11109 2025-10-26 09:31:07 +01:00
github-actions[bot]
3253b2e569 Merge pull request #11107 from firefly-iii/release-1761395685
🤖 Automatically merge the PR into the develop branch.
2025-10-25 14:34:54 +02:00
JC5
11ac955303 🤖 Auto commit for release 'develop' on 2025-10-25 2025-10-25 14:34:46 +02:00
James Cole
caf9a31bc4 Replace version with build time. 2025-10-25 14:30:22 +02:00
github-actions[bot]
8c84ab5855 Merge pull request #11106 from firefly-iii/release-1761394994
🤖 Automatically merge the PR into the develop branch.
2025-10-25 14:23:23 +02:00
JC5
91a56a7396 🤖 Auto commit for release 'develop' on 2025-10-25 2025-10-25 14:23:14 +02:00
James Cole
f5806ea6de Fix #11102 2025-10-25 14:09:44 +02:00
James Cole
60b3692ac9 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-10-25 11:50:43 +02:00
James Cole
0bdb4f2e69 Fix https://github.com/orgs/firefly-iii/discussions/11104 2025-10-25 11:50:34 +02:00
github-actions[bot]
f89f50c2db Merge pull request #11101 from firefly-iii/release-1761383546
🤖 Automatically merge the PR into the develop branch.
2025-10-25 11:12:35 +02:00
JC5
394df46961 🤖 Auto commit for release 'develop' on 2025-10-25 2025-10-25 11:12:26 +02:00
James Cole
535e5e4f50 Catch null pointer. 2025-10-25 11:08:07 +02:00
James Cole
00ba2a46d2 Fix #11063 2025-10-25 09:20:21 +02:00
James Cole
a3ff26e3e4 Fix https://github.com/firefly-iii/firefly-iii/issues/11096 2025-10-23 16:54:13 +02:00
James Cole
3388cb6f66 Merge pull request #11085 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-fd296dbd23
Bump vite from 7.1.9 to 7.1.11 in the npm_and_yarn group across 1 directory
2025-10-21 07:13:37 +02:00
dependabot[bot]
1c3c9377ca Bump vite in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 7.1.9 to 7.1.11
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.11
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 22:58:03 +00:00
github-actions[bot]
54aeb4b4ef Merge pull request #11084 from firefly-iii/release-1760930902
🤖 Automatically merge the PR into the develop branch.
2025-10-20 05:28:30 +02:00
JC5
9eb3ad62dd 🤖 Auto commit for release 'develop' on 2025-10-20 2025-10-20 05:28:22 +02:00
github-actions[bot]
4f0e978687 Merge pull request #11060 from firefly-iii/release-1760325917
🤖 Automatically merge the PR into the develop branch.
2025-10-13 05:25:26 +02:00
JC5
e1cf9f7a79 🤖 Auto commit for release 'develop' on 2025-10-13 2025-10-13 05:25:17 +02:00
James Cole
7ce055a22c Merge pull request #11056 from ctrl-f5/feat/account-attachment-list-request
account/attachments endpoint use request object for pagination, add test
2025-10-12 20:15:00 +02:00
Nicky De Maeyer
7bd915930c account/attachments endpoint use request object for pagination, add test 2025-10-12 19:54:47 +02:00
github-actions[bot]
75aa2d99fd Merge pull request #11055 from firefly-iii/release-1760278017
🤖 Automatically merge the PR into the develop branch.
2025-10-12 16:07:07 +02:00
JC5
f52bc0e242 🤖 Auto commit for release 'develop' on 2025-10-12 2025-10-12 16:06:57 +02:00
James Cole
55cf924794 Another fix for #11054 2025-10-12 16:02:14 +02:00
James Cole
df3e4a6554 Fix #11054 2025-10-12 12:25:21 +02:00
James Cole
7c4ada458e Merge pull request #11052 from ctrl-f5/fix/incorrect-validator-function
correct validator function to check for errors + `Account\ShowControllerTest`
2025-10-12 06:47:19 +02:00
Nicky De Maeyer
2a4a98dd10 use the correct validator function to check for errors, add a test for ShowController 2025-10-11 23:02:54 +02:00
github-actions[bot]
a3bf845851 Merge pull request #11051 from firefly-iii/release-1760189013
🤖 Automatically merge the PR into the develop branch.
2025-10-11 15:23:39 +02:00
JC5
78e832cdba 🤖 Auto commit for release 'develop' on 2025-10-11 2025-10-11 15:23:33 +02:00
James Cole
d47e4c4f24 Fix #11050 2025-10-11 15:17:51 +02:00
174 changed files with 1926 additions and 1161 deletions

View File

@@ -402,16 +402,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.88.2",
"version": "v3.89.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99"
"reference": "f34967da2866ace090a2b447de1f357356474573"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99",
"reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/f34967da2866ace090a2b447de1f357356474573",
"reference": "f34967da2866ace090a2b447de1f357356474573",
"shasum": ""
},
"require": {
@@ -426,7 +426,6 @@
"php": "^7.4 || ^8.0",
"react/child-process": "^0.6.6",
"react/event-loop": "^1.5",
"react/promise": "^3.3",
"react/socket": "^1.16",
"react/stream": "^1.4",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
@@ -494,7 +493,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.88.2"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.1"
},
"funding": [
{
@@ -502,7 +501,7 @@
"type": "github"
}
],
"time": "2025-09-27T00:24:15+00:00"
"time": "2025-10-24T12:05:10+00:00"
},
{
"name": "psr/container",
@@ -1252,16 +1251,16 @@
},
{
"name": "symfony/console",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"shasum": ""
},
"require": {
@@ -1326,7 +1325,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.4"
"source": "https://github.com/symfony/console/tree/v7.3.5"
},
"funding": [
{
@@ -1346,7 +1345,7 @@
"type": "tidelift"
}
],
"time": "2025-09-22T15:31:00+00:00"
"time": "2025-10-14T15:46:26+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1647,16 +1646,16 @@
},
{
"name": "symfony/finder",
"version": "v7.3.2",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
"reference": "9f696d2f1e340484b4683f7853b273abff94421f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
"reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"shasum": ""
},
"require": {
@@ -1691,7 +1690,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v7.3.2"
"source": "https://github.com/symfony/finder/tree/v7.3.5"
},
"funding": [
{
@@ -1711,7 +1710,7 @@
"type": "tidelift"
}
],
"time": "2025-07-15T13:41:35+00:00"
"time": "2025-10-15T18:45:57+00:00"
},
{
"name": "symfony/options-resolver",

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
@@ -79,20 +79,26 @@ class AccountController extends Controller
* @throws FireflyException
* @throws FireflyException
*/
public function accounts(AutocompleteRequest $request): JsonResponse
public function accounts(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $data['date'];
$return = [];
$timer = Timer::getInstance();
$timer->start(sprintf('AC accounts "%s"', $query));
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
[
'types' => $types,
'query' => $query,
'date' => $date,
'limit' => $limit,
]
= $request->attributes->all();
$date ??= today(config('app.timezone'));
// set date to end-of-day for account balance. so it is at $date 23:59:59
$date->endOfDay();
$return = [];
$timer = Timer::getInstance();
$timer->start(sprintf('AC accounts "%s"', $query));
$result = $this->repository->searchAccount((string)$query, $types, $limit);
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
/** @var Account $account */
@@ -111,17 +117,17 @@ class AccountController extends Controller
}
$return[] = [
'id' => (string) $account->id,
'id' => (string)$account->id,
'name' => $account->name,
'name_with_balance' => $nameWithBalance,
'active' => $account->active,
'type' => $account->accountType->type,
'currency_id' => (string) $useCurrency->id,
'currency_id' => (string)$useCurrency->id,
'currency_name' => $useCurrency->name,
'currency_code' => $useCurrency->code,
'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $useCurrency->decimal_places,
'account_currency_id' => (string) $currency->id,
'account_currency_id' => (string)$currency->id,
'account_currency_name' => $currency->name,
'account_currency_code' => $currency->code,
'account_currency_symbol' => $currency->symbol,
@@ -134,8 +140,8 @@ class AccountController extends Controller
$return,
static function (array $left, array $right) {
$order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
$posA = (int) array_search($left['type'], $order, true);
$posB = (int) array_search($right['type'], $order, true);
$posA = (int)array_search($left['type'], $order, true);
$posB = (int)array_search($right['type'], $order, true);
return $posA - $posB;
}

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@@ -61,10 +61,9 @@ class BillController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getBillsAC
*/
public function bills(AutocompleteRequest $request): JsonResponse
public function bills(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchBill($data['query'], $this->parameters->get('limit'));
$result = $this->repository->searchBill($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(
static fn (Bill $item) => [
'id' => (string) $item->id,

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
@@ -61,10 +61,9 @@ class BudgetController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getBudgetsAC
*/
public function budgets(AutocompleteRequest $request): JsonResponse
public function budgets(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchBudget($data['query'], $this->parameters->get('limit'));
$result = $this->repository->searchBudget($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(
static fn (Budget $item) => [
'id' => (string) $item->id,

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
@@ -61,10 +61,9 @@ class CategoryController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCategoriesAC
*/
public function categories(AutocompleteRequest $request): JsonResponse
public function categories(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit'));
$result = $this->repository->searchCategory($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(
static fn (Category $item) => [
'id' => (string) $item->id,

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use Deprecated;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionCurrency;
@@ -62,10 +63,9 @@ class CurrencyController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCurrenciesAC
*/
public function currencies(AutocompleteRequest $request): JsonResponse
public function currencies(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$collection = $this->repository->searchCurrency($data['query'], $this->parameters->get('limit'));
$collection = $this->repository->searchCurrency($request->attributes->get('query'), $request->attributes->get('limit'));
$result = [];
/** @var TransactionCurrency $currency */

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
@@ -61,11 +61,10 @@ class ObjectGroupController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getObjectGroupsAC
*/
public function objectGroups(AutocompleteRequest $request): JsonResponse
public function objectGroups(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$return = [];
$result = $this->repository->search($data['query'], $this->parameters->get('limit'));
$result = $this->repository->search($request->attributes->get('query'), $request->attributes->get('limit'));
/** @var ObjectGroup $objectGroup */
foreach ($result as $objectGroup) {

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
@@ -64,10 +64,9 @@ class PiggyBankController extends Controller
);
}
public function piggyBanks(AutocompleteRequest $request): JsonResponse
public function piggyBanks(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
$piggies = $this->piggyRepository->searchPiggyBank($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var PiggyBank $piggy */
@@ -90,10 +89,9 @@ class PiggyBankController extends Controller
return response()->api($response);
}
public function piggyBanksWithBalance(AutocompleteRequest $request): JsonResponse
public function piggyBanksWithBalance(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
$piggies = $this->piggyRepository->searchPiggyBank($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var PiggyBank $piggy */

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
@@ -57,10 +57,9 @@ class RecurrenceController extends Controller
);
}
public function recurring(AutocompleteRequest $request): JsonResponse
public function recurring(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$recurrences = $this->repository->searchRecurrence($data['query'], $this->parameters->get('limit'));
$recurrences = $this->repository->searchRecurrence($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var Recurrence $recurrence */

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
@@ -57,10 +57,9 @@ class RuleController extends Controller
);
}
public function rules(AutocompleteRequest $request): JsonResponse
public function rules(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$rules = $this->repository->searchRule($data['query'], $this->parameters->get('limit'));
$rules = $this->repository->searchRule($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var Rule $rule */

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
@@ -57,10 +57,9 @@ class RuleGroupController extends Controller
);
}
public function ruleGroups(AutocompleteRequest $request): JsonResponse
public function ruleGroups(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$groups = $this->repository->searchRuleGroup($data['query'], $this->parameters->get('limit'));
$groups = $this->repository->searchRuleGroup($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var RuleGroup $group */

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
@@ -57,10 +57,9 @@ class TagController extends Controller
);
}
public function tags(AutocompleteRequest $request): JsonResponse
public function tags(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchTags($data['query'], $this->parameters->get('limit'));
$result = $this->repository->searchTags($request->attributes->get('query'), $request->attributes->get('limit'));
$array = [];
/** @var Tag $tag */

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
@@ -64,10 +64,9 @@ class TransactionController extends Controller
);
}
public function transactions(AutocompleteRequest $request): JsonResponse
public function transactions(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit'));
$result = $this->repository->searchJournalDescriptions($request->attributes->get('query'), $request->attributes->get('limit'));
// limit and unique
$filtered = $result->unique('description');
@@ -86,13 +85,12 @@ class TransactionController extends Controller
return response()->api($array);
}
public function transactionsWithID(AutocompleteRequest $request): JsonResponse
public function transactionsWithID(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$result = new Collection();
if (is_numeric($data['query'])) {
if (is_numeric($request->attributes->get('query'))) {
// search for group, not journal.
$firstResult = $this->groupRepository->find((int) $data['query']);
$firstResult = $this->groupRepository->find((int) $request->attributes->get('query'));
if ($firstResult instanceof TransactionGroup) {
// group may contain multiple journals, each a result:
foreach ($firstResult->transactionJournals as $journal) {
@@ -100,8 +98,8 @@ class TransactionController extends Controller
}
}
}
if (!is_numeric($data['query'])) {
$result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit'));
if (!is_numeric($request->attributes->get('query'))) {
$result = $this->repository->searchJournalDescriptions($request->attributes->get('query'), $request->attributes->get('limit'));
}
// limit and unique

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
@@ -55,10 +55,9 @@ class TransactionTypeController extends Controller
);
}
public function transactionTypes(AutocompleteRequest $request): JsonResponse
public function transactionTypes(AutocompleteApiRequest $request): JsonResponse
{
$data = $request->getData();
$types = $this->repository->searchTypes($data['query'], $this->parameters->get('limit'));
$types = $this->repository->searchTypes($request->attributes->get('query'), $request->attributes->get('limit'));
$array = [];
/** @var TransactionType $type */

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
@@ -83,15 +83,13 @@ class BudgetController extends Controller
*
* @throws FireflyException
*/
public function overview(SameDateRequest $request): JsonResponse
public function overview(DateRangeRequest $request): JsonResponse
{
$params = $request->getAll();
/** @var Carbon $start */
$start = $params['start'];
$start = $request->attributes->get('start');
/** @var Carbon $end */
$end = $params['end'];
$end = $request->attributes->get('end');
// code from FrontpageChartGenerator, but not in separate class
$budgets = $this->repository->getActiveBudgets();

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
@@ -80,13 +80,13 @@ class CategoryController extends Controller
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
*/
public function overview(SameDateRequest $request): JsonResponse
public function overview(DateRangeRequest $request): JsonResponse
{
/** @var Carbon $start */
$start = $this->parameters->get('start');
$start = $request->attributes->get('start');
/** @var Carbon $end */
$end = $this->parameters->get('end');
$end = $request->attributes->get('end');
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value]);
$currencies = [];
$return = [];

View File

@@ -29,6 +29,7 @@ use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Exceptions\BadHttpHeaderException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\AbstractTransformer;
@@ -159,7 +160,7 @@ abstract class Controller extends BaseController
/** @var User $user */
$user = auth()->user();
$pageSize = (int)app('preferences')->getForUser($user, 'listPageSize', 50)->data;
$pageSize = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}
}

View File

@@ -46,6 +46,7 @@ use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -102,7 +103,7 @@ class DestroyController extends Controller
default => throw new FireflyException(sprintf('200033: This endpoint can\'t handle object "%s"', $objects)),
};
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Account;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -60,7 +61,7 @@ class DestroyController extends Controller
public function destroy(Account $account): JsonResponse
{
$this->repository->destroy($account, null);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Account;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -69,22 +70,25 @@ class ListController extends Controller
);
}
public function attachments(Account $account): JsonResponse
public function attachments(PaginationRequest $request, Account $account): JsonResponse
{
$manager = $this->getManager();
$pageSize = $this->parameters->get('limit');
[
'limit' => $limit,
'offset' => $offset,
'page' => $page,
] = $request->attributes->all();
$collection = $this->repository->getAttachments($account);
$count = $collection->count();
$attachments = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$attachments = $collection->slice($offset, $limit);
// make paginator:
$paginator = new LengthAwarePaginator($attachments, $count, $pageSize, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
$paginator->setPath(route('api.v1.accounts.attachments', [$account->id]).$this->buildParams());
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
@@ -92,18 +96,21 @@ class ListController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
public function piggyBanks(Account $account): JsonResponse
public function piggyBanks(PaginationRequest $request, Account $account): JsonResponse
{
// create some objects:
$manager = $this->getManager();
// types to get, page size:
$pageSize = $this->parameters->get('limit');
[
'limit' => $limit,
'offset' => $offset,
'page' => $page,
] = $request->attributes->all();
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getPiggyBanks($account);
$count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$piggyBanks = $collection->slice(($page - 1) * $limit, $limit);
// enrich
/** @var User $admin */
@@ -113,12 +120,12 @@ class ListController extends Controller
$piggyBanks = $enrichment->enrich($piggyBanks);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($piggyBanks, $count, $limit, $page);
$paginator->setPath(route('api.v1.accounts.piggy-banks', [$account->id]).$this->buildParams());
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
// $transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Account\UpdateRequest;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
@@ -74,7 +75,7 @@ class UpdateController extends Controller
$account = $this->repository->update($account, $data);
$manager = $this->getManager();
$account->refresh();
app('preferences')->mark();
Preferences::mark();
// enrich
/** @var User $admin */

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Middleware\ApiDemoUser;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -74,7 +75,7 @@ class DestroyController extends Controller
}
$this->repository->destroy($attachment);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Bill;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Bill $bill): JsonResponse
{
$this->repository->destroy($bill);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Budget;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Budget $budget): JsonResponse
{
$this->repository->destroy($budget);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -71,7 +72,7 @@ class DestroyController extends Controller
throw new FireflyException('20028: The budget limit does not belong to the budget.');
}
$this->blRepository->destroyBudgetLimit($budgetLimit);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -172,7 +172,6 @@ class ShowController extends Controller
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Category;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Category $category): JsonResponse
{
$this->repository->destroy($category);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
@@ -75,6 +76,9 @@ class DestroyController extends Controller
if ($exchangeRate instanceof CurrencyExchangeRate) {
$this->repository->deleteRate($exchangeRate);
}
if (!$exchangeRate instanceof CurrencyExchangeRate) {
throw new FireflyException('Bla');
}
return response()->json([], 204);
}

View File

@@ -82,7 +82,6 @@ class UpdateController extends Controller
$exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date);
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\ObjectGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -64,7 +65,7 @@ class DestroyController extends Controller
public function destroy(ObjectGroup $objectGroup): JsonResponse
{
$this->repository->destroy($objectGroup);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\PiggyBank;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(PiggyBank $piggyBank): JsonResponse
{
$this->repository->destroy($piggyBank);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Recurrence $recurrence): JsonResponse
{
$this->repository->destroy($recurrence);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Rule;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -65,7 +66,7 @@ class DestroyController extends Controller
public function destroy(Rule $rule): JsonResponse
{
$this->ruleRepository->destroy($rule);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\RuleGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -65,7 +66,7 @@ class DestroyController extends Controller
public function destroy(RuleGroup $ruleGroup): JsonResponse
{
$this->ruleGroupRepository->destroy($ruleGroup, null);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Tag;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -65,7 +66,7 @@ class DestroyController extends Controller
public function destroy(Tag $tag): JsonResponse
{
$this->repository->destroy($tag);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -32,6 +32,7 @@ use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -92,7 +93,7 @@ class DestroyController extends Controller
$this->groupRepository->destroy($transactionGroup);
app('preferences')->mark();
Preferences::mark();
/** @var Account $account */
foreach ($accounts as $account) {
@@ -112,7 +113,7 @@ class DestroyController extends Controller
public function destroyJournal(TransactionJournal $transactionJournal): JsonResponse
{
$this->repository->destroyJournal($transactionJournal);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -33,6 +33,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Rules\IsDuplicateTransaction;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -107,7 +108,7 @@ class StoreController extends Controller
throw new ValidationException($validator);
}
app('preferences')->mark();
Preferences::mark();
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));

View File

@@ -30,6 +30,7 @@ use FireflyIII\Events\UpdatedTransactionGroup;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
@@ -79,7 +80,7 @@ class UpdateController extends Controller
$newHash = $this->groupRepository->getCompareHash($transactionGroup);
$manager = $this->getManager();
app('preferences')->mark();
Preferences::mark();
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
$runRecalculations = $oldHash !== $newHash;

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;
@@ -89,7 +90,7 @@ class DestroyController extends Controller
}
$this->repository->destroy($currency);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionCurrency;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\StoreRequest;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer;
@@ -71,7 +72,7 @@ class StoreController extends Controller
$currency = $this->repository->store($request->getAll());
if (true === $request->boolean('default')) {
$this->repository->makePrimary($currency);
app('preferences')->mark();
Preferences::mark();
}
$manager = $this->getManager();

View File

@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\UpdateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer;
@@ -105,7 +106,7 @@ class UpdateController extends Controller
$this->repository->enable($currency);
$this->repository->makePrimary($currency);
app('preferences')->mark();
Preferences::mark();
$manager = $this->getManager();
$currency->refreshForUser($user);
@@ -172,14 +173,13 @@ class UpdateController extends Controller
$currency = $this->repository->update($currency, $data);
app('preferences')->mark();
Preferences::mark();
$manager = $this->getManager();
$currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionLink;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\TransactionJournalLink;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -66,7 +67,7 @@ class DestroyController extends Controller
public function destroy(TransactionJournalLink $link): JsonResponse
{
$this->repository->destroyLink($link);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\LinkType;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -73,7 +74,7 @@ class DestroyController extends Controller
throw new FireflyException('200020: Link type cannot be changed.');
}
$this->repository->destroy($linkType);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\UserGroup\UpdateRequest;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -59,7 +60,7 @@ class UpdateController extends Controller
$data = $request->getData();
$userGroup = $this->repository->update($userGroup, $data);
$userGroup->refresh();
app('preferences')->mark();
Preferences::mark();
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters);

View File

@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\User\PreferenceStoreRequest;
use FireflyIII\Api\V1\Requests\User\PreferenceUpdateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Preference;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Transformers\PreferenceTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -52,7 +53,7 @@ class PreferencesController extends Controller
*/
public function index(): JsonResponse
{
$collection = app('preferences')->all();
$collection = Preferences::all();
$manager = $this->getManager();
$count = $collection->count();
$pageSize = $this->parameters->get('limit');
@@ -110,7 +111,7 @@ class PreferencesController extends Controller
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
$pref = app('preferences')->set($data['name'], $data['data']);
$pref = Preferences::set($data['name'], $data['data']);
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
@@ -135,7 +136,7 @@ class PreferencesController extends Controller
$manager = $this->getManager();
$data = $request->getAll();
$pref = app('preferences')->set($preference->name, $data['data']);
$pref = Preferences::set($preference->name, $data['data']);
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\Webhook;
use FireflyIII\Models\WebhookAttempt;
use FireflyIII\Models\WebhookMessage;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -70,7 +71,7 @@ class DestroyController extends Controller
Log::channel('audit')->info(sprintf('User destroys webhook #%d.', $webhook->id));
$this->repository->destroy($webhook);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}
@@ -101,7 +102,7 @@ class DestroyController extends Controller
Log::channel('audit')->info(sprintf('User destroys webhook #%d, message #%d, attempt #%d.', $webhook->id, $message->id, $attempt->id));
$this->repository->destroyAttempt($attempt);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}
@@ -128,7 +129,7 @@ class DestroyController extends Controller
Log::channel('audit')->info(sprintf('User destroys webhook #%d, message #%d.', $webhook->id, $message->id));
$this->repository->destroyMessage($message);
app('preferences')->mark();
Preferences::mark();
return response()->json([], 204);
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/*
* AutocompleteApiRequest.php
* Copyright (c) 2025 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\Api\V1\Requests\Autocomplete;
use FireflyIII\Api\V1\Requests\AggregateFormRequest;
use FireflyIII\Api\V1\Requests\DateRequest;
use FireflyIII\Api\V1\Requests\Generic\QueryRequest;
use FireflyIII\Api\V1\Requests\Models\Account\AccountTypesApiRequest;
use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Models\Account;
use Override;
class AutocompleteApiRequest extends AggregateFormRequest
{
#[Override]
protected function getRequests(): array
{
return [
DateRequest::class,
[PaginationRequest::class, 'sort_class' => Account::class],
AccountTypesApiRequest::class,
QueryRequest::class,
];
}
}

View File

@@ -31,6 +31,8 @@ use Illuminate\Foundation\Http\FormRequest;
/**
* Class AutocompleteRequest
*
* @deprecated
*/
class AutocompleteRequest extends FormRequest
{

View File

@@ -32,6 +32,8 @@ use Illuminate\Foundation\Http\FormRequest;
* Request class for end points that require date parameters.
*
* Class SameDateRequest
*
* @deprecated Replaced by DateRangeRequest
*/
class SameDateRequest extends FormRequest
{

View File

@@ -39,7 +39,11 @@ class DateRangeRequest extends ApiRequest
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
if ($validator->failed()) {
// set null values
$this->attributes->set('start', null);
$this->attributes->set('end', null);
return;
}
$start = $this->getCarbonDate('start')?->startOfDay();

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Carbon\Carbon;
use Illuminate\Validation\Validator;
class DateRequest extends ApiRequest
@@ -38,8 +39,7 @@ class DateRequest extends ApiRequest
{
$validator->after(
function (Validator $validator): void {
$this->attributes->set('date', null);
if (!$validator->valid()) {
if ($validator->failed()) {
return;
}
$date = $this->getCarbonDate('date')?->endOfDay();
@@ -47,7 +47,7 @@ class DateRequest extends ApiRequest
// if we also have a range, date must be in that range
$start = $this->attributes->get('start');
$end = $this->attributes->get('end');
if ($date && $start && $end && !$date->between($start, $end)) {
if ($date instanceof Carbon && $start instanceof Carbon && $end instanceof Carbon && !$date->between($start, $end)) {
$validator->errors()->add('date', (string)trans('validation.between_date'));
}

View File

@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
/*
* QueryRequest.php
* Copyright (c) 2025 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\Api\V1\Requests\Generic;
use FireflyIII\Api\V1\Requests\ApiRequest;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Validation\Validator;
class QueryRequest extends ApiRequest
{
use ChecksLogin;
use ConvertsDataTypes;
public function rules(): array
{
return [
'query' => sprintf('min:1|max:50|%s', $this->required),
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if ($validator->failed()) {
return;
}
$query = $this->convertString('query');
$this->attributes->set('query', $query);
}
);
}
}

View File

@@ -33,6 +33,8 @@ use Illuminate\Foundation\Http\FormRequest;
* Request class for end points that require a date parameter.
*
* Class SingleDateRequest
*
* @deprecated
*/
class SingleDateRequest extends FormRequest
{

View File

@@ -42,7 +42,7 @@ class AccountTypeApiRequest extends ApiRequest
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
if ($validator->failed()) {
return;
}

View File

@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
/*
* AccountTypeApiRequest.php
* Copyright (c) 2025 https://github.com/ctrl-f5
*
* 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\Api\V1\Requests\Models\Account;
use FireflyIII\Api\V1\Requests\ApiRequest;
use FireflyIII\Rules\Account\IsValidAccountTypeList;
use FireflyIII\Support\Http\Api\AccountFilter;
use Illuminate\Validation\Validator;
class AccountTypesApiRequest extends ApiRequest
{
use AccountFilter;
public function rules(): array
{
// sprintf('in:%s', implode(',', array_keys($this->types))),
return [
'types' => new IsValidAccountTypeList(),
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if ($validator->failed()) {
return;
}
$type = $this->convertString('types', 'all');
$this->attributes->add([
'types' => $this->mapAccountTypes($type),
]);
}
);
}
}

View File

@@ -57,7 +57,7 @@ class PaginationRequest extends ApiRequest
{
$validator->after(
function (Validator $validator): void {
if (!$validator->valid()) {
if ($validator->failed()) {
return;
}

View File

@@ -28,6 +28,7 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -47,7 +48,7 @@ class CorrectsFrontpageAccounts extends Command
/** @var User $user */
foreach ($users as $user) {
$preference = app('preferences')->getForUser($user, 'frontpageAccounts');
$preference = Preferences::getForUser($user, 'frontpageAccounts');
if (null !== $preference) {
$this->fixPreference($preference);
}
@@ -79,6 +80,6 @@ class CorrectsFrontpageAccounts extends Command
}
}
}
app('preferences')->setForUser($preference->user, 'frontpageAccounts', $fixed);
Preferences::setForUser($preference->user, 'frontpageAccounts', $fixed);
}
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Console\Commands\Correction;
use Exception;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -54,10 +55,10 @@ class CreatesAccessTokens extends Command
/** @var User $user */
foreach ($users as $user) {
$pref = app('preferences')->getForUser($user, 'access_token');
$pref = Preferences::getForUser($user, 'access_token');
if (null === $pref) {
$token = $user->generateAccessToken();
app('preferences')->setForUser($user, 'access_token', $token);
Preferences::setForUser($user, 'access_token', $token);
$this->friendlyInfo(sprintf('Generated access token for user %s', $user->email));
++$count;
}

View File

@@ -33,6 +33,7 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -114,7 +115,7 @@ class UpgradesBillsToRules extends Command
$this->ruleRepository->setUser($user);
/** @var Preference $lang */
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
$lang = Preferences::getForUser($user, 'language', 'en_US');
$language = null !== $lang->data && !is_array($lang->data) ? (string) $lang->data : 'en_US';
$groupTitle = (string) trans('firefly.rulegroup_for_bills_title', [], $language);
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
@@ -79,7 +80,7 @@ trait VerifiesAccessToken
return false;
}
$accessToken = app('preferences')->getForUser($user, 'access_token');
$accessToken = Preferences::getForUser($user, 'access_token');
if (null === $accessToken) {
Log::error(sprintf('User #%d has no access token, so cannot access command line options.', $userId));

View File

@@ -84,8 +84,10 @@ class AttachmentFactory
return $attachment;
}
public function setUser(User $user): void
public function setUser(User $user): static
{
$this->user = $user;
return $this;
}
}

View File

@@ -221,10 +221,26 @@ class TransactionJournalFactory
];
Log::debug('Source info:', $sourceInfo);
Log::debug('Destination info:', $destInfo);
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo, $sourceAccount);
$destinationAccount = null;
$sourceAccount = null;
if (TransactionTypeEnum::DEPOSIT->value === $type->type) {
Log::debug('Transaction type is deposit, start with destination first.');
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo, $destinationAccount);
}
if (TransactionTypeEnum::DEPOSIT->value !== $type->type) {
Log::debug('Transaction type is not deposit, start with source first.');
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo, $sourceAccount);
}
Log::debug('Done with getAccount(2x)');
// there is a safety catch here. If either account is NULL, they will be replaced with the cash account.
if (null === $destinationAccount) {
Log::warning('Destination account is NULL, will replace with cash account.');
$destinationAccount = $this->accountRepository->getCashAccount();
}
// this is the moment for a reconciliation sanity check (again).
if (TransactionTypeEnum::RECONCILIATION->value === $type->type) {

View File

@@ -30,6 +30,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Notifications\User\TransactionCreation;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Transformers\TransactionGroupTransformer;
use Illuminate\Support\Facades\Notification;
@@ -52,7 +53,7 @@ class AutomationHandler
$user = $repository->find($event->userId);
/** @var bool $sendReport */
$sendReport = app('preferences')->getForUser($user, 'notification_transaction_creation', false)->data;
$sendReport = Preferences::getForUser($user, 'notification_transaction_creation', false)->data;
if (false === $sendReport) {
app('log')->debug('Not sending report, because config says so.');

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Handlers\Events\Model;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Notifications\User\RuleActionFailed;
use FireflyIII\Support\Facades\Preferences;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
@@ -42,7 +43,7 @@ class RuleHandler
$rule = $ruleAction->rule;
/** @var bool $preference */
$preference = app('preferences')->getForUser($rule->user, 'notification_rule_action_failures', true)->data;
$preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
if (false === $preference) {
return;
}
@@ -71,7 +72,7 @@ class RuleHandler
$rule = $ruleAction->rule;
/** @var bool $preference */
$preference = app('preferences')->getForUser($rule->user, 'notification_rule_action_failures', true)->data;
$preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
if (false === $preference) {
return;
}

View File

@@ -27,6 +27,7 @@ use FireflyIII\Enums\WebhookTrigger;
use FireflyIII\Events\RequestedSendWebhookMessages;
use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
@@ -105,10 +106,18 @@ class StoredGroupEventHandler
/** @var TransactionJournal $journal */
foreach ($event->transactionGroup->transactionJournals as $journal) {
/** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', '0')->first();
/** @var null|Transaction $dest */
$dest = $journal->transactions()->where('amount', '>', '0')->first();
$repository->deleteStatisticsForModel($source->account, $journal->date);
$repository->deleteStatisticsForModel($dest->account, $journal->date);
if (null !== $source) {
$repository->deleteStatisticsForModel($source->account, $journal->date);
}
if (null !== $dest) {
$repository->deleteStatisticsForModel($dest->account, $journal->date);
}
$categories = $journal->categories;
$tags = $journal->tags;
$budgets = $journal->budgets;

View File

@@ -51,6 +51,7 @@ use FireflyIII\Notifications\User\UserLogin;
use FireflyIII\Notifications\User\UserNewPassword;
use FireflyIII\Notifications\User\UserRegistration as UserRegistrationNotification;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Auth\Events\Login;
use Illuminate\Support\Facades\Log;
@@ -174,9 +175,10 @@ class UserEventHandler
$user = $event->user;
if ($repository->hasRole($user, 'demo')) {
// set user back to English.
app('preferences')->setForUser($user, 'language', 'en_US');
app('preferences')->setForUser($user, 'locale', 'equal');
app('preferences')->mark();
Preferences::setForUser($user, 'language', 'en_US');
Preferences::setForUser($user, 'locale', 'equal');
Preferences::setForUser($user, 'anonymous', false);
Preferences::mark();
}
}
@@ -188,7 +190,7 @@ class UserEventHandler
return; // do not email demo user.
}
$list = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
$list = Preferences::getForUser($user, 'login_ip_history', [])->data;
if (!is_array($list)) {
$list = [];
}
@@ -217,12 +219,12 @@ class UserEventHandler
$list[$index]['notified'] = true;
}
app('preferences')->setForUser($user, 'login_ip_history', $list);
Preferences::setForUser($user, 'login_ip_history', $list);
}
public function sendAdminRegistrationNotification(RegisteredUser $event): void
{
$sendMail = (bool) app('fireflyconfig')->get('notification_admin_new_reg', true)->data;
$sendMail = (bool)app('fireflyconfig')->get('notification_admin_new_reg', true)->data;
if ($sendMail) {
$owner = $event->owner;
@@ -257,7 +259,7 @@ class UserEventHandler
$newEmail = $event->newEmail;
$oldEmail = $event->oldEmail;
$user = $event->user;
$token = app('preferences')->getForUser($user, 'email_change_confirm_token', 'invalid');
$token = Preferences::getForUser($user, 'email_change_confirm_token', 'invalid');
$url = route('profile.confirm-email-change', [$token->data]);
try {
@@ -281,8 +283,8 @@ class UserEventHandler
$newEmail = $event->newEmail;
$oldEmail = $event->oldEmail;
$user = $event->user;
$token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid');
$hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $oldEmail));
$token = Preferences::getForUser($user, 'email_change_undo_token', 'invalid');
$hashed = hash('sha256', sprintf('%s%s', (string)config('app.key'), $oldEmail));
$url = route('profile.undo-email-change', [$token->data, $hashed]);
try {
@@ -365,7 +367,7 @@ class UserEventHandler
*/
public function sendRegistrationMail(RegisteredUser $event): void
{
$sendMail = (bool) app('fireflyconfig')->get('notification_user_new_reg', true)->data;
$sendMail = (bool)app('fireflyconfig')->get('notification_user_new_reg', true)->data;
if ($sendMail) {
try {
Notification::send($event->user, new UserRegistrationNotification());
@@ -455,7 +457,7 @@ class UserEventHandler
try {
/** @var array $preference */
$preference = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
$preference = Preferences::getForUser($user, 'login_ip_history', [])->data;
} catch (FireflyException $e) {
// don't care.
app('log')->error($e->getMessage());
@@ -491,8 +493,8 @@ class UserEventHandler
$preference = array_values($preference);
/** @var bool $send */
$send = app('preferences')->getForUser($user, 'notification_user_login', true)->data;
app('preferences')->setForUser($user, 'login_ip_history', $preference);
$send = Preferences::getForUser($user, 'notification_user_login', true)->data;
Preferences::setForUser($user, 'login_ip_history', $preference);
if (false === $inArray && true === $send) {
event(new DetectedNewIPAddress($user));

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Fiscal;
use Carbon\Carbon;
use FireflyIII\Support\Facades\Preferences;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -40,7 +41,7 @@ class FiscalHelper implements FiscalHelperInterface
*/
public function __construct()
{
$this->useCustomFiscalYear = (bool) app('preferences')->get('customFiscalYear', false)->data;
$this->useCustomFiscalYear = (bool) Preferences::get('customFiscalYear', false)->data;
}
/**
@@ -74,7 +75,7 @@ class FiscalHelper implements FiscalHelperInterface
// get start mm-dd. Then create a start date in the year passed.
$startDate = clone $date;
if (true === $this->useCustomFiscalYear) {
$prefStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
$prefStartStr = Preferences::get('fiscalYearStart', '01-01')->data;
if (is_array($prefStartStr)) {
$prefStartStr = '01-01';
}

View File

@@ -96,11 +96,10 @@ class CreateController extends Controller
];
// interest calculation periods:
$interestPeriods = [
'daily' => (string) trans('firefly.interest_calc_daily'),
'monthly' => (string) trans('firefly.interest_calc_monthly'),
'yearly' => (string) trans('firefly.interest_calc_yearly'),
];
$interestPeriods = [];
foreach (config('firefly.interest_periods') as $period) {
$interestPeriods[$period] = trans(sprintf('firefly.interest_calc_%s', $period));
}
// pre fill some data
$request->session()->flash(

View File

@@ -108,11 +108,10 @@ class EditController extends Controller
];
// interest calculation periods:
$interestPeriods = [
'daily' => (string) trans('firefly.interest_calc_daily'),
'monthly' => (string) trans('firefly.interest_calc_monthly'),
'yearly' => (string) trans('firefly.interest_calc_yearly'),
];
$interestPeriods = [];
foreach (config('firefly.interest_periods') as $period) {
$interestPeriods[$period] = trans(sprintf('firefly.interest_calc_%s', $period));
}
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('accounts.edit.fromUpdate')) {

View File

@@ -77,6 +77,7 @@ abstract class Controller extends BaseController
View::share('DEMO_USERNAME', config('firefly.demo_username'));
View::share('DEMO_PASSWORD', config('firefly.demo_password'));
View::share('FF_VERSION', config('firefly.version'));
View::share('FF_BUILD_TIME', config('firefly.build_time'));
// is webhooks enabled?
View::share('featuringWebhooks', true === config('firefly.feature_flags.webhooks') && true === config('firefly.allow_webhooks'));
@@ -131,6 +132,7 @@ abstract class Controller extends BaseController
$this->primaryCurrency = null;
// get shown-intro-preference:
if (auth()->check()) {
View::share('anonymous', Steam::anonymous());
$this->primaryCurrency = Amount::getPrimaryCurrency();
$language = Steam::getLanguage();
$locale = Steam::getLocale();

View File

@@ -81,11 +81,11 @@ class DebugController extends Controller
*/
public function displayError(): void
{
app('log')->debug('This is a test message at the DEBUG level.');
app('log')->info('This is a test message at the INFO level.');
Log::debug('This is a test message at the DEBUG level.');
Log::info('This is a test message at the INFO level.');
Log::notice('This is a test message at the NOTICE level.');
app('log')->warning('This is a test message at the WARNING level.');
app('log')->error('This is a test message at the ERROR level.');
Log::warning('This is a test message at the WARNING level.');
Log::error('This is a test message at the ERROR level.');
Log::critical('This is a test message at the CRITICAL level.');
Log::alert('This is a test message at the ALERT level.');
Log::emergency('This is a test message at the EMERGENCY level.');
@@ -187,6 +187,8 @@ class DebugController extends Controller
return [
'php_version' => PHP_VERSION,
'php_os' => PHP_OS,
'build_time' => config('firefly.build_time'),
'build_time_nice' => Carbon::parse(config('firefly.build_time'), 'Europe/Amsterdam')->setTimezone('Europe/Amsterdam')->format('Y-m-d H:i:s e'),
'uname' => php_uname('m'),
'interface' => PHP_SAPI,
'bits' => PHP_INT_SIZE * 8,
@@ -212,11 +214,11 @@ class DebugController extends Controller
try {
if (file_exists('/var/www/counter-main.txt')) {
$return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
app('log')->debug(sprintf('build is now "%s"', $return['build']));
Log::debug(sprintf('build is now "%s"', $return['build']));
}
} catch (Exception $e) {
app('log')->debug('Could not check build counter, but thats ok.');
app('log')->warning($e->getMessage());
Log::debug('Could not check build counter, but thats ok.');
Log::warning($e->getMessage());
}
try {
@@ -224,8 +226,8 @@ class DebugController extends Controller
$return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
}
} catch (Exception $e) {
app('log')->debug('Could not check build date, but thats ok.');
app('log')->warning($e->getMessage());
Log::debug('Could not check build date, but thats ok.');
Log::warning($e->getMessage());
}
if ('' !== (string) env('BASE_IMAGE_BUILD')) { // @phpstan-ignore-line
$return['base_build'] = env('BASE_IMAGE_BUILD'); // @phpstan-ignore-line
@@ -282,7 +284,7 @@ class DebugController extends Controller
$parts = Steam::getLocaleArray(Steam::getLocale());
foreach ($parts as $code) {
$code = trim($code);
app('log')->debug(sprintf('Trying to set %s', $code));
Log::debug(sprintf('Trying to set %s', $code));
$result = setlocale(LC_ALL, $code);
$localeAttempts[$code] = $result === $code;
}

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -114,6 +115,7 @@ class JavascriptController extends Controller
'currencyCode' => $currency->code,
'currencySymbol' => $currency->symbol,
'accountingLocaleInfo' => $accounting,
'anonymous' => var_export(Steam::anonymous(), true),
'language' => $lang,
'dateRangeTitle' => $dateRange['title'],
'locale' => $locale,

View File

@@ -268,7 +268,6 @@ class CreateController extends Controller
public function store(RuleFormRequest $request)
{
$data = $request->getRuleData();
$rule = $this->ruleRepos->store($data);
session()->flash('success_url', route('rules.select-transactions', [$rule->id]));
session()->flash('success', (string) trans('firefly.stored_new_rule', ['title' => $rule->title]));
@@ -283,6 +282,9 @@ class CreateController extends Controller
if ((int) $request->get('bill_id') > 0) {
return redirect($this->getPreviousUrl('bills.create.url'));
}
if (true === $data['run_after_form']) {
return redirect(route('rules.select-transactions', [$rule->id]));
}
$redirect = redirect($this->getPreviousUrl('rules.create.url'));

View File

@@ -205,6 +205,11 @@ class EditController extends Controller
session()->flash('success', (string) trans('firefly.updated_rule', ['title' => $rule->title]));
app('preferences')->mark();
$redirect = redirect($this->getPreviousUrl('rules.edit.url'));
if (true === $data['run_after_form']) {
return redirect(route('rules.select-transactions', [$rule->id]));
}
if (1 === (int) $request->get('return_to_edit')) {
session()->put('rules.edit.fromUpdate', true);

View File

@@ -54,6 +54,7 @@ class RuleFormRequest extends FormRequest
'description' => $this->stringWithNewlines('description'),
'stop_processing' => $this->boolean('stop_processing'),
'strict' => $this->boolean('strict'),
'run_after_form' => $this->boolean('run_after_form'),
'triggers' => $this->getRuleTriggerData(),
'actions' => $this->getRuleActionData(),
];
@@ -140,16 +141,17 @@ class RuleFormRequest extends FormRequest
// initial set of rules:
$rules = [
'title' => 'required|min:1|max:255|uniqueObjectForUser:rules,title',
'description' => 'min:1|max:32768|nullable',
'stop_processing' => 'boolean',
'rule_group_id' => 'required|belongsToUser:rule_groups',
'trigger' => 'required|in:store-journal,update-journal,manual-activation',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => sprintf('required_if:triggers.*.type,%s|max:1024|min:1|ruleTriggerValue', $contextTriggers),
'actions.*.type' => 'required|in:'.implode(',', $validActions),
'actions.*.value' => [sprintf('required_if:actions.*.type,%s|min:0|max:1024', $contextActions), new IsValidActionExpression(), 'ruleActionValue'],
'strict' => 'in:0,1',
'title' => 'required|min:1|max:255|uniqueObjectForUser:rules,title',
'description' => 'min:1|max:32768|nullable',
'stop_processing' => 'boolean',
'rule_group_id' => 'required|belongsToUser:rule_groups',
'trigger' => 'required|in:store-journal,update-journal,manual-activation',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => sprintf('required_if:triggers.*.type,%s|max:1024|min:1|ruleTriggerValue', $contextTriggers),
'actions.*.type' => 'required|in:'.implode(',', $validActions),
'actions.*.value' => [sprintf('required_if:actions.*.type,%s|min:0|max:1024', $contextActions), new IsValidActionExpression(), 'ruleActionValue'],
'strict' => 'in:0,1',
'run_after_form' => 'in:0,1',
];
/** @var null|Rule $rule */

View File

@@ -31,6 +31,8 @@ use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Safe\Exceptions\FilesystemException;
use Safe\Exceptions\JsonException;
use Symfony\Component\Mailer\Exception\TransportException;
use function Safe\file_get_contents;
@@ -54,7 +56,7 @@ class MailError extends Job implements ShouldQueue
$debug = $this->exception;
unset($debug['stackTrace'], $debug['headers']);
app('log')->error(sprintf('Exception is: %s', json_encode($debug)));
Log::error(sprintf('Exception is: %s', json_encode($debug)));
}
/**
@@ -90,17 +92,17 @@ class MailError extends Job implements ShouldQueue
} catch (Exception|TransportException $e) {
$message = $e->getMessage();
if (str_contains($message, 'Bcc')) {
app('log')->warning('[Bcc] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
Log::warning('[Bcc] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
return;
}
if (str_contains($message, 'RFC 2822')) {
app('log')->warning('[RFC] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
Log::warning('[RFC] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
return;
}
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
}
}
}
@@ -125,11 +127,25 @@ class MailError extends Job implements ShouldQueue
if (!file_exists($file)) {
Log::debug(sprintf('Wrote new file in "%s"', $file));
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
try {
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
} catch (FilesystemException $e) {
Log::warning(sprintf('[a] Could not write file "%s": %s', $file, $e->getMessage()));
} catch (JsonException $e) {
Log::warning(sprintf('[b] Could not parse file "%s": %s', $file, $e->getMessage()));
}
}
if (file_exists($file)) {
Log::debug(sprintf('Read file in "%s"', $file));
$limits = json_decode(file_get_contents($file), true);
try {
$limits = json_decode(file_get_contents($file), true);
} catch (FilesystemException $e) {
Log::warning(sprintf('[c] Could not read file "%s": %s', $file, $e->getMessage()));
} catch (JsonException $e) {
Log::warning(sprintf('[d] Could not parse file "%s": %s', $file, $e->getMessage()));
}
}
// limit reached?
foreach ($types as $type => $info) {
@@ -157,7 +173,14 @@ class MailError extends Job implements ShouldQueue
}
++$limits[$type]['sent'];
}
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
try {
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
} catch (FilesystemException $e) {
Log::warning(sprintf('[c] Could not write file "%s": %s', $file, $e->getMessage()));
} catch (JsonException $e) {
Log::warning(sprintf('[c] Could not parse file "%s": %s', $file, $e->getMessage()));
}
Log::debug('No limits reached, return FALSE.');
return false;

View File

@@ -0,0 +1,56 @@
<?php
/*
* IsValidAccountType.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Rules\Account;
use Closure;
use FireflyIII\Support\Http\Api\AccountFilter;
use Illuminate\Contracts\Validation\ValidationRule;
use Override;
class IsValidAccountTypeList implements ValidationRule
{
use AccountFilter;
#[Override]
public function validate(string $attribute, mixed $value, Closure $fail): void
{
// only check the type.
$values = [];
if (is_string($value)) {
$values = explode(',', $value);
}
if (!is_array($values)) {
$fail('validation.invalid_account_list')->translate();
}
$keys = array_keys($this->types);
foreach ($values as $entry) {
$entry = (string) $entry;
if (!in_array($entry, $keys, true)) {
$fail('validation.invalid_account_list')->translate();
}
}
}
}

View File

@@ -88,6 +88,7 @@ trait JournalServiceTrait
// the account that Firefly III creates must be "creatable", aka select the one we can create from the list just in case
$creatableType = $this->getCreatableType($expectedTypes[$transactionType]);
Log::debug(sprintf('Creatable type is "%s"', $creatableType), $expectedTypes[$transactionType]);
// if the result is NULL but the ID is set, an account could exist of the wrong type.
// that data can be used to create a new account of the right type.
@@ -227,9 +228,11 @@ trait JournalServiceTrait
}
// find by preferred type.
Log::debug('Find by preferred type.');
$result = $this->accountRepository->findByName($data['name'], [$types[0]]);
// or any expected type.
Log::debug('Find by any expected type.');
$result ??= $this->accountRepository->findByName($data['name'], $types);
if (null !== $result) {

View File

@@ -163,6 +163,7 @@ class Amount
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{
$amount = Steam::anonymous() ? '0' : $amount;
$locale = Steam::getLocale();
$rounded = Steam::bcround($amount, $decimalPlaces);
$coloured ??= true;

View File

@@ -634,10 +634,10 @@ trait PeriodOverview
$currencySymbol = $journal['currency_symbol'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$foreignCurrencyId = $journal['foreign_currency_id'];
$amount = $journal['amount'] ?? '0';
$amount = (string) ($journal['amount'] ?? '0');
if ($this->convertToPrimary && $currencyId !== $this->primaryCurrency->id && $foreignCurrencyId !== $this->primaryCurrency->id) {
$amount = $journal['pc_amount'] ?? '0';
$amount = (string) ($journal['pc_amount'] ?? '0');
$currencyId = $this->primaryCurrency->id;
$currencyCode = $this->primaryCurrency->code;
$currencyName = $this->primaryCurrency->name;
@@ -650,7 +650,7 @@ trait PeriodOverview
$currencyName = $journal['foreign_currency_name'];
$currencySymbol = $journal['foreign_currency_symbol'];
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
$amount = $journal['foreign_amount'] ?? '0';
$amount = (string) ($journal['foreign_amount'] ?? '0');
}
$return[$currencyId] ??= [
'amount' => '0',

View File

@@ -154,6 +154,9 @@ class BudgetLimitEnrichment implements EnrichmentInterface
$this->start = $this->collection->min('start_date') ?? Carbon::now()->startOfMonth();
$this->end = $this->collection->max('end_date') ?? Carbon::now()->endOfMonth();
// #11096 make sure that the max end date is also at the end of the day,
$this->end->endOfDay();
/** @var BudgetLimit $limit */
foreach ($this->collection as $limit) {
$id = (int)$limit->id;

View File

@@ -88,7 +88,7 @@ trait UserGroupTrait
public function setUserGroup(UserGroup $userGroup): void
{
if (null === $this->user) {
Log::warning(sprintf('User is not set in repository %s', static::class));
Log::warning(sprintf('User is not set in repository %s. This does not have to be a problem.', static::class));
}
$this->userGroup = $userGroup;
}

View File

@@ -52,13 +52,23 @@ class QueryParser implements QueryParserInterface
$inQuotes = false;
$fieldName = '';
$prohibited = false;
while ($this->position < strlen($this->query)) {
$char = $this->query[$this->position];
$chrArray = preg_split('//u', $this->query, -1, PREG_SPLIT_NO_EMPTY);
$count = count($chrArray);
while ($this->position < $count) {
$char = $chrArray[$this->position];
$nextChar = $chrArray[$this->position + 1] ?? '';
// Log::debug(sprintf('Char #%d: %s', $this->position, $char));
// If we're in a quoted string, we treat all characters except another quote as ordinary characters
if ($inQuotes) {
if ('\\' === $char && '"' === $nextChar) {
// Log::debug('BACKSLASH!');
// escaped quote, pretend it's a normal char and continue two places (skipping the actual character).
$tokenUnderConstruction .= '\\'.$nextChar;
$this->position += 2;
continue;
}
if ('"' !== $char) {
$tokenUnderConstruction .= $char;
++$this->position;
@@ -67,11 +77,9 @@ class QueryParser implements QueryParserInterface
}
// char is "
++$this->position;
Log::debug(sprintf('Constructed token: %s', $tokenUnderConstruction));
return new NodeResult(
$this->createNode($tokenUnderConstruction, $fieldName, $prohibited),
false
);
return new NodeResult($this->createNode($tokenUnderConstruction, $fieldName, $prohibited), false);
}
switch ($char) {
@@ -197,9 +205,13 @@ class QueryParser implements QueryParserInterface
private function createNode(string $token, string $fieldName, bool $prohibited): Node
{
if ('' !== $fieldName) {
Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
// OK dus hoe trim je \" correct?
$token = ltrim($token, ':"');
$token = rtrim($token, '"');
if (!str_ends_with($token, '\"')) {
$token = rtrim($token, '"');
}
$token = str_replace('\"', '"', $token);
Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
return new FieldNode(trim($fieldName), trim($token), $prohibited);
}

View File

@@ -627,6 +627,19 @@ class Steam
return $locale;
}
public function anonymous(): bool // get preference
{
$singleton = PreferencesSingleton::getInstance();
$cached = $singleton->getPreference('anonymous');
if (null !== $cached) {
return $cached;
}
$anonymous = app('preferences')->get('anonymous', config('firefly.default_preferences.anonymous', false))->data;
$singleton->setPreference('anonymous', $anonymous);
return $anonymous;
}
public function getLocaleArray(string $locale): array
{
return [

View File

@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.4.3 - 2025-11-01
### Added
- [PR 10993](https://github.com/firefly-iii/firefly-iii/pull/10993) (use correct translation key for category report income table) reported by @ctrl-f5
- [PR 11028](https://github.com/firefly-iii/firefly-iii/pull/11028) (Adding Latin American Currency Support) reported by @codearena-bot
- [PR 11039](https://github.com/firefly-iii/firefly-iii/pull/11039) (proposal for improved request handling) reported by @ctrl-f5
- [PR 11041](https://github.com/firefly-iii/firefly-iii/pull/11041) (Add XML mimetypes to the allowedMimes list) reported by @jreyesr
- [Issue 11102](https://github.com/firefly-iii/firefly-iii/issues/11102) (Allow to redact account totals in web ui) reported by @edvgui
- [Issue 11132](https://github.com/firefly-iii/firefly-iii/issues/11132) (Add a 6 month interest period) reported by @CiramorDev
### Fixed
- [Issue 11109](https://github.com/firefly-iii/firefly-iii/issues/11109) (Could not find a transaction currency with code "Korean Won"/"Russian ruble") reported by @mattephi
- [PR 11019](https://github.com/firefly-iii/firefly-iii/pull/11019) (fix issue 11015 set end date time to end of day) reported by @ctrl-f5
- [PR 11024](https://github.com/firefly-iii/firefly-iii/pull/11024) (improved balance range date handling) reported by @ctrl-f5
- [Issue 11031](https://github.com/firefly-iii/firefly-iii/issues/11031) (Rule with trigger "When a transaction is created" being triggered on transaction updates) reported by @pvieira84
- [Issue 11038](https://github.com/firefly-iii/firefly-iii/issues/11038) (Missing date formats when using "MTD" on the frontpage) reported by @cristiangrossano
- [Issue 11042](https://github.com/firefly-iii/firefly-iii/issues/11042) (Option to apply rules on a specific date range has disappeared from the UI) reported by @angelbarrera92
- [PR 11052](https://github.com/firefly-iii/firefly-iii/pull/11052) (correct validator function to check for errors + `Account\ShowControllerTest`) reported by @ctrl-f5
- [Issue 11054](https://github.com/firefly-iii/firefly-iii/issues/11054) (Autocreation of revenue account when depositing to liability) reported by @Mr-Kanister
- [Issue 11063](https://github.com/firefly-iii/firefly-iii/issues/11063) ("bcadd: argument must be of type string, int given" when viewing categories or tags) reported by @df911
- [Discussion 11104](https://github.com/orgs/firefly-iii/discussions/11104) (Personal Access Token failing on 6.4.2 for data-importer) started by @marcoblancas
- [Discussion 11122](https://github.com/orgs/firefly-iii/discussions/11122) (Convenient Rules Creation) started by @viewmatic2025
- [Issue 11134](https://github.com/firefly-iii/firefly-iii/issues/11134) (Rules are not applied if description in quotes) reported by @beatbesmer
### Security
- Debug route is now behind 2FA
### API
- [Issue 11050](https://github.com/firefly-iii/firefly-iii/issues/11050) (Dev Version: `/api/v1/accounts/get/$id` requires (optional) `start` parameter, throws error otherwise) reported by @dreautall
- [PR 11056](https://github.com/firefly-iii/firefly-iii/pull/11056) (account/attachments endpoint use request object for pagination, add test) reported by @ctrl-f5
- [Issue 11096](https://github.com/firefly-iii/firefly-iii/issues/11096) (Budget Limit API ignores transactions on the last day of the month) reported by @edbingo
## 6.4.2 - 2055-10-07

311
composer.lock generated
View File

@@ -1878,16 +1878,16 @@
},
{
"name": "laravel/framework",
"version": "v12.33.0",
"version": "v12.36.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "124efc5f09d4668a4dc13f94a1018c524a58bcb1"
"reference": "cad110d7685fbab990a6bb8184d0cfd847d7c4d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/124efc5f09d4668a4dc13f94a1018c524a58bcb1",
"reference": "124efc5f09d4668a4dc13f94a1018c524a58bcb1",
"url": "https://api.github.com/repos/laravel/framework/zipball/cad110d7685fbab990a6bb8184d0cfd847d7c4d8",
"reference": "cad110d7685fbab990a6bb8184d0cfd847d7c4d8",
"shasum": ""
},
"require": {
@@ -1999,7 +1999,7 @@
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
"opis/json-schema": "^2.4.1",
"orchestra/testbench-core": "^10.6.5",
"orchestra/testbench-core": "^10.7.0",
"pda/pheanstalk": "^5.0.6|^7.0.0",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0",
@@ -2093,7 +2093,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-10-07T14:30:39+00:00"
"time": "2025-10-29T14:20:57+00:00"
},
{
"name": "laravel/passport",
@@ -2296,16 +2296,16 @@
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.5",
"version": "v2.0.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "3832547db6e0e2f8bb03d4093857b378c66eceed"
"reference": "038ce42edee619599a1debb7e81d7b3759492819"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3832547db6e0e2f8bb03d4093857b378c66eceed",
"reference": "3832547db6e0e2f8bb03d4093857b378c66eceed",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819",
"reference": "038ce42edee619599a1debb7e81d7b3759492819",
"shasum": ""
},
"require": {
@@ -2353,7 +2353,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2025-09-22T17:29:40+00:00"
"time": "2025-10-09T13:42:30+00:00"
},
{
"name": "laravel/slack-notification-channel",
@@ -2485,20 +2485,20 @@
},
{
"name": "lcobucci/clock",
"version": "3.4.0",
"version": "3.5.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/clock.git",
"reference": "f91d84f65cb3e974988bbe872b5da8ca132a155f"
"reference": "a3139d9e97d47826f27e6a17bb63f13621f86058"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lcobucci/clock/zipball/f91d84f65cb3e974988bbe872b5da8ca132a155f",
"reference": "f91d84f65cb3e974988bbe872b5da8ca132a155f",
"url": "https://api.github.com/repos/lcobucci/clock/zipball/a3139d9e97d47826f27e6a17bb63f13621f86058",
"reference": "a3139d9e97d47826f27e6a17bb63f13621f86058",
"shasum": ""
},
"require": {
"php": "~8.3.0 || ~8.4.0",
"php": "~8.3.0 || ~8.4.0 || ~8.5.0",
"psr/clock": "^1.0"
},
"provide": {
@@ -2506,7 +2506,7 @@
},
"require-dev": {
"infection/infection": "^0.31",
"lcobucci/coding-standard": "^11.1.0",
"lcobucci/coding-standard": "^11.2.0",
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan": "^2.0.0",
"phpstan/phpstan-deprecation-rules": "^2.0.0",
@@ -2533,7 +2533,7 @@
"description": "Yet another clock abstraction",
"support": {
"issues": "https://github.com/lcobucci/clock/issues",
"source": "https://github.com/lcobucci/clock/tree/3.4.0"
"source": "https://github.com/lcobucci/clock/tree/3.5.0"
},
"funding": [
{
@@ -2545,26 +2545,26 @@
"type": "patreon"
}
],
"time": "2025-10-08T18:00:48+00:00"
"time": "2025-10-27T09:03:17+00:00"
},
{
"name": "lcobucci/jwt",
"version": "5.5.0",
"version": "5.6.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/jwt.git",
"reference": "a835af59b030d3f2967725697cf88300f579088e"
"reference": "bb3e9f21e4196e8afc41def81ef649c164bca25e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e",
"reference": "a835af59b030d3f2967725697cf88300f579088e",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/bb3e9f21e4196e8afc41def81ef649c164bca25e",
"reference": "bb3e9f21e4196e8afc41def81ef649c164bca25e",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"ext-sodium": "*",
"php": "~8.2.0 || ~8.3.0 || ~8.4.0",
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"psr/clock": "^1.0"
},
"require-dev": {
@@ -2606,7 +2606,7 @@
],
"support": {
"issues": "https://github.com/lcobucci/jwt/issues",
"source": "https://github.com/lcobucci/jwt/tree/5.5.0"
"source": "https://github.com/lcobucci/jwt/tree/5.6.0"
},
"funding": [
{
@@ -2618,7 +2618,7 @@
"type": "patreon"
}
],
"time": "2025-01-26T21:29:45+00:00"
"time": "2025-10-17T11:30:53+00:00"
},
{
"name": "league/commonmark",
@@ -2811,16 +2811,16 @@
},
{
"name": "league/csv",
"version": "9.26.0",
"version": "9.27.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
"reference": "7fce732754d043f3938899e5183e2d0f3d31b571"
"reference": "26de738b8fccf785397d05ee2fc07b6cd8749797"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/7fce732754d043f3938899e5183e2d0f3d31b571",
"reference": "7fce732754d043f3938899e5183e2d0f3d31b571",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/26de738b8fccf785397d05ee2fc07b6cd8749797",
"reference": "26de738b8fccf785397d05ee2fc07b6cd8749797",
"shasum": ""
},
"require": {
@@ -2898,7 +2898,7 @@
"type": "github"
}
],
"time": "2025-10-01T11:24:54+00:00"
"time": "2025-10-25T08:35:20+00:00"
},
{
"name": "league/event",
@@ -2956,16 +2956,16 @@
},
{
"name": "league/flysystem",
"version": "3.30.0",
"version": "3.30.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "2203e3151755d874bb2943649dae1eb8533ac93e"
"reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e",
"reference": "2203e3151755d874bb2943649dae1eb8533ac93e",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c139fd65c1f796b926f4aec0df37f6caa959a8da",
"reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da",
"shasum": ""
},
"require": {
@@ -3033,9 +3033,9 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.30.0"
"source": "https://github.com/thephpleague/flysystem/tree/3.30.1"
},
"time": "2025-06-25T13:29:59+00:00"
"time": "2025-10-20T15:35:26+00:00"
},
{
"name": "league/flysystem-local",
@@ -3476,22 +3476,22 @@
},
{
"name": "mailersend/laravel-driver",
"version": "v2.11.0",
"version": "v2.12.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-laravel-driver.git",
"reference": "63acebb5064745076df27b1a80423986b6d7b69e"
"reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/63acebb5064745076df27b1a80423986b6d7b69e",
"reference": "63acebb5064745076df27b1a80423986b6d7b69e",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/15e1ec41e29e65d3ca226929c65804190aaa93eb",
"reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"mailersend/mailersend": "^0.34.0",
"mailersend/mailersend": "^0.35.0",
"nyholm/psr7": "^1.5",
"php": ">=8.0",
"php-http/guzzle7-adapter": "^1.0",
@@ -3539,22 +3539,22 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-laravel-driver/issues",
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.11.0"
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.12.0"
},
"time": "2025-06-04T08:47:41+00:00"
"time": "2025-10-28T14:59:16+00:00"
},
{
"name": "mailersend/mailersend",
"version": "v0.34.0",
"version": "v0.35.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-php.git",
"reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab"
"reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
"reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/f1696cf9e727e9503fbc5882d2a111bd966ad276",
"reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276",
"shasum": ""
},
"require": {
@@ -3605,9 +3605,9 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-php/issues",
"source": "https://github.com/mailersend/mailersend-php/tree/v0.34.0"
"source": "https://github.com/mailersend/mailersend-php/tree/v0.35.0"
},
"time": "2025-06-04T07:53:52+00:00"
"time": "2025-10-28T13:11:43+00:00"
},
{
"name": "monolog/monolog",
@@ -3819,25 +3819,25 @@
},
{
"name": "nette/schema",
"version": "v1.3.2",
"version": "v1.3.3",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "da801d52f0354f70a638673c4a0f04e16529431d"
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
"reference": "da801d52f0354f70a638673c4a0f04e16529431d",
"url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004",
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004",
"shasum": ""
},
"require": {
"nette/utils": "^4.0",
"php": "8.1 - 8.4"
"php": "8.1 - 8.5"
},
"require-dev": {
"nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^1.0",
"phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.8"
},
"type": "library",
@@ -3847,6 +3847,9 @@
}
},
"autoload": {
"psr-4": {
"Nette\\": "src"
},
"classmap": [
"src/"
]
@@ -3875,9 +3878,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.3.2"
"source": "https://github.com/nette/schema/tree/v1.3.3"
},
"time": "2024-10-06T23:10:23+00:00"
"time": "2025-10-30T22:57:59+00:00"
},
{
"name": "nette/utils",
@@ -4069,31 +4072,31 @@
},
{
"name": "nunomaduro/termwind",
"version": "v2.3.1",
"version": "v2.3.2",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
"reference": "dfa08f390e509967a15c22493dc0bac5733d9123"
"reference": "eb61920a53057a7debd718a5b89c2178032b52c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123",
"reference": "dfa08f390e509967a15c22493dc0bac5733d9123",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/eb61920a53057a7debd718a5b89c2178032b52c0",
"reference": "eb61920a53057a7debd718a5b89c2178032b52c0",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.2",
"symfony/console": "^7.2.6"
"symfony/console": "^7.3.4"
},
"require-dev": {
"illuminate/console": "^11.44.7",
"laravel/pint": "^1.22.0",
"illuminate/console": "^11.46.1",
"laravel/pint": "^1.25.1",
"mockery/mockery": "^1.6.12",
"pestphp/pest": "^2.36.0 || ^3.8.2",
"phpstan/phpstan": "^1.12.25",
"pestphp/pest": "^2.36.0 || ^3.8.4",
"phpstan/phpstan": "^1.12.32",
"phpstan/phpstan-strict-rules": "^1.6.2",
"symfony/var-dumper": "^7.2.6",
"symfony/var-dumper": "^7.3.4",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
@@ -4136,7 +4139,7 @@
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
"source": "https://github.com/nunomaduro/termwind/tree/v2.3.1"
"source": "https://github.com/nunomaduro/termwind/tree/v2.3.2"
},
"funding": [
{
@@ -4152,7 +4155,7 @@
"type": "github"
}
],
"time": "2025-05-08T08:14:37+00:00"
"time": "2025-10-18T11:10:27+00:00"
},
{
"name": "nyholm/psr7",
@@ -6416,16 +6419,16 @@
},
{
"name": "symfony/cache",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "bf8afc8ffd4bfd3d9c373e417f041d9f1e5b863f"
"reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/bf8afc8ffd4bfd3d9c373e417f041d9f1e5b863f",
"reference": "bf8afc8ffd4bfd3d9c373e417f041d9f1e5b863f",
"url": "https://api.github.com/repos/symfony/cache/zipball/4a55feb59664f49042a0824c0f955e2f4c1412ad",
"reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad",
"shasum": ""
},
"require": {
@@ -6494,7 +6497,7 @@
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v7.3.4"
"source": "https://github.com/symfony/cache/tree/v7.3.5"
},
"funding": [
{
@@ -6514,7 +6517,7 @@
"type": "tidelift"
}
],
"time": "2025-09-11T10:12:26+00:00"
"time": "2025-10-16T13:55:38+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -6668,16 +6671,16 @@
},
{
"name": "symfony/console",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"shasum": ""
},
"require": {
@@ -6742,7 +6745,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.4"
"source": "https://github.com/symfony/console/tree/v7.3.5"
},
"funding": [
{
@@ -6762,7 +6765,7 @@
"type": "tidelift"
}
],
"time": "2025-09-22T15:31:00+00:00"
"time": "2025-10-14T15:46:26+00:00"
},
{
"name": "symfony/css-selector",
@@ -7207,16 +7210,16 @@
},
{
"name": "symfony/finder",
"version": "v7.3.2",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
"reference": "9f696d2f1e340484b4683f7853b273abff94421f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
"reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"shasum": ""
},
"require": {
@@ -7251,7 +7254,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v7.3.2"
"source": "https://github.com/symfony/finder/tree/v7.3.5"
},
"funding": [
{
@@ -7271,7 +7274,7 @@
"type": "tidelift"
}
],
"time": "2025-07-15T13:41:35+00:00"
"time": "2025-10-15T18:45:57+00:00"
},
{
"name": "symfony/http-client",
@@ -7453,16 +7456,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "c061c7c18918b1b64268771aad04b40be41dd2e6"
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/c061c7c18918b1b64268771aad04b40be41dd2e6",
"reference": "c061c7c18918b1b64268771aad04b40be41dd2e6",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
"shasum": ""
},
"require": {
@@ -7512,7 +7515,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.3.4"
"source": "https://github.com/symfony/http-foundation/tree/v7.3.5"
},
"funding": [
{
@@ -7532,20 +7535,20 @@
"type": "tidelift"
}
],
"time": "2025-09-16T08:38:17+00:00"
"time": "2025-10-24T21:42:11+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "b796dffea7821f035047235e076b60ca2446e3cf"
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/b796dffea7821f035047235e076b60ca2446e3cf",
"reference": "b796dffea7821f035047235e076b60ca2446e3cf",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
"shasum": ""
},
"require": {
@@ -7630,7 +7633,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.3.4"
"source": "https://github.com/symfony/http-kernel/tree/v7.3.5"
},
"funding": [
{
@@ -7650,20 +7653,20 @@
"type": "tidelift"
}
],
"time": "2025-09-27T12:32:17+00:00"
"time": "2025-10-28T10:19:01+00:00"
},
{
"name": "symfony/mailer",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "ab97ef2f7acf0216955f5845484235113047a31d"
"reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d",
"reference": "ab97ef2f7acf0216955f5845484235113047a31d",
"url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba",
"reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba",
"shasum": ""
},
"require": {
@@ -7714,7 +7717,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v7.3.4"
"source": "https://github.com/symfony/mailer/tree/v7.3.5"
},
"funding": [
{
@@ -7734,7 +7737,7 @@
"type": "tidelift"
}
],
"time": "2025-09-17T05:51:54+00:00"
"time": "2025-10-24T14:27:20+00:00"
},
{
"name": "symfony/mailgun-mailer",
@@ -9453,16 +9456,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v7.3.4",
"version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb"
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"shasum": ""
},
"require": {
@@ -9516,7 +9519,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.4"
"source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
},
"funding": [
{
@@ -9536,7 +9539,7 @@
"type": "tidelift"
}
],
"time": "2025-09-11T10:12:26+00:00"
"time": "2025-09-27T09:00:46+00:00"
},
{
"name": "symfony/var-exporter",
@@ -9815,16 +9818,16 @@
},
{
"name": "twig/twig",
"version": "v3.21.1",
"version": "v3.22.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d"
"reference": "4509984193026de413baf4ba80f68590a7f2c51d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d",
"reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4509984193026de413baf4ba80f68590a7f2c51d",
"reference": "4509984193026de413baf4ba80f68590a7f2c51d",
"shasum": ""
},
"require": {
@@ -9878,7 +9881,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.21.1"
"source": "https://github.com/twigphp/Twig/tree/v3.22.0"
},
"funding": [
{
@@ -9890,7 +9893,7 @@
"type": "tidelift"
}
],
"time": "2025-05-03T07:21:55+00:00"
"time": "2025-10-29T15:56:47+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -10052,28 +10055,28 @@
},
{
"name": "webmozart/assert",
"version": "1.11.0",
"version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-date": "*",
"ext-filter": "*",
"php": "^7.2 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^8.5.13"
"suggest": {
"ext-intl": "",
"ext-simplexml": "",
"ext-spl": ""
},
"type": "library",
"extra": {
@@ -10104,9 +10107,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
"source": "https://github.com/webmozarts/assert/tree/1.12.1"
},
"time": "2022-06-03T18:03:27+00:00"
"time": "2025-10-29T15:56:20+00:00"
}
],
"packages-dev": [
@@ -10549,16 +10552,16 @@
},
{
"name": "driftingly/rector-laravel",
"version": "2.0.7",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/driftingly/rector-laravel.git",
"reference": "625dc02cee08d47ecf0ac86de2f02a55026cf34e"
"reference": "abc336cbf06f53d90ab74cecfd319379fc55d408"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/625dc02cee08d47ecf0ac86de2f02a55026cf34e",
"reference": "625dc02cee08d47ecf0ac86de2f02a55026cf34e",
"url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/abc336cbf06f53d90ab74cecfd319379fc55d408",
"reference": "abc336cbf06f53d90ab74cecfd319379fc55d408",
"shasum": ""
},
"require": {
@@ -10578,9 +10581,9 @@
"description": "Rector upgrades rules for Laravel Framework",
"support": {
"issues": "https://github.com/driftingly/rector-laravel/issues",
"source": "https://github.com/driftingly/rector-laravel/tree/2.0.7"
"source": "https://github.com/driftingly/rector-laravel/tree/2.1.1"
},
"time": "2025-08-19T20:49:47+00:00"
"time": "2025-10-23T13:53:44+00:00"
},
{
"name": "fakerphp/faker",
@@ -11036,16 +11039,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.6.1",
"version": "v5.6.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
"reference": "3a454ca033b9e06b63282ce19562e892747449bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
"reference": "3a454ca033b9e06b63282ce19562e892747449bb",
"shasum": ""
},
"require": {
@@ -11088,9 +11091,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
},
"time": "2025-08-13T20:13:15+00:00"
"time": "2025-10-21T19:32:17+00:00"
},
{
"name": "phar-io/manifest",
@@ -11815,16 +11818,16 @@
},
{
"name": "phpunit/phpunit",
"version": "12.4.1",
"version": "12.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194"
"reference": "a94ea4d26d865875803b23aaf78c3c2c670ea2ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
"reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a94ea4d26d865875803b23aaf78c3c2c670ea2ea",
"reference": "a94ea4d26d865875803b23aaf78c3c2c670ea2ea",
"shasum": ""
},
"require": {
@@ -11892,7 +11895,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.1"
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.2"
},
"funding": [
{
@@ -11916,20 +11919,20 @@
"type": "tidelift"
}
],
"time": "2025-10-09T14:08:29+00:00"
"time": "2025-10-30T08:41:39+00:00"
},
{
"name": "rector/rector",
"version": "2.2.2",
"version": "2.2.7",
"source": {
"type": "git",
"url": "https://github.com/rectorphp/rector.git",
"reference": "5b353f7457b9a0c63fc91ef340f5d119a40991ed"
"reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/5b353f7457b9a0c63fc91ef340f5d119a40991ed",
"reference": "5b353f7457b9a0c63fc91ef340f5d119a40991ed",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/022038537838bc8a4e526af86c2d6e38eaeff7ef",
"reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef",
"shasum": ""
},
"require": {
@@ -11968,7 +11971,7 @@
],
"support": {
"issues": "https://github.com/rectorphp/rector/issues",
"source": "https://github.com/rectorphp/rector/tree/2.2.2"
"source": "https://github.com/rectorphp/rector/tree/2.2.7"
},
"funding": [
{
@@ -11976,7 +11979,7 @@
"type": "github"
}
],
"time": "2025-10-09T19:50:20+00:00"
"time": "2025-10-29T15:46:12+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@@ -78,8 +78,8 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2025-10-11',
'build_time' => 1760159380,
'version' => '6.4.3',
'build_time' => 1761889776,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.
@@ -182,6 +182,7 @@ return [
'darkMode' => 'browser',
'list_length' => 10, // to be removed if v1 is cancelled.
'default_preferences' => [
'anonymous' => false,
'frontpageAccounts' => [],
'listPageSize' => 50,
'currencyPreference' => 'EUR',
@@ -308,7 +309,7 @@ return [
// "period must be in this list" values
'bill_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
'interest_periods' => ['weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
'interest_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
// settings to translate X to Y
'range_to_repeat_freq' => [

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Database\Factories;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Models\AccountType;
use Illuminate\Database\Eloquent\Factories\Factory;
class AccountFactory extends Factory
{
public function definition(): array
{
return [
'name' => $this->faker->name(),
'active' => true,
];
}
public function withType(AccountTypeEnum $type): static
{
return $this->for(AccountType::where('type', $type->value)->first());
}
}

View File

@@ -11,34 +11,36 @@ return new class extends Migration
*/
public function up(): void
{
Schema::create('period_statistics', function (Blueprint $table) {
$table->id();
$table->timestamps();
if (!Schema::hasTable('period_statistics')) {
Schema::create('period_statistics', function (Blueprint $table) {
$table->id();
$table->timestamps();
// reference to user group id.
$table->bigInteger('user_group_id', false, true);
// reference to user group id.
$table->bigInteger('user_group_id', false, true);
$table->integer('primary_statable_id', false, true)->nullable();
$table->string('primary_statable_type', 255)->nullable();
$table->integer('primary_statable_id', false, true)->nullable();
$table->string('primary_statable_type', 255)->nullable();
$table->integer('secondary_statable_id', false, true)->nullable();
$table->string('secondary_statable_type', 255)->nullable();
$table->integer('secondary_statable_id', false, true)->nullable();
$table->string('secondary_statable_type', 255)->nullable();
$table->integer('tertiary_statable_id', false, true)->nullable();
$table->string('tertiary_statable_type', 255)->nullable();
$table->integer('tertiary_statable_id', false, true)->nullable();
$table->string('tertiary_statable_type', 255)->nullable();
$table->integer('transaction_currency_id', false, true);
$table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade');
$table->integer('transaction_currency_id', false, true);
$table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade');
$table->dateTime('start')->nullable();
$table->string('start_tz', 50)->nullable();
$table->dateTime('end')->nullable();
$table->string('end_tz', 50)->nullable();
$table->string('type',255);
$table->integer('count', false, true)->default(0);
$table->decimal('amount', 32, 12);
$table->foreign('user_group_id')->references('id')->on('user_groups')->onDelete('cascade');
});
$table->dateTime('start')->nullable();
$table->string('start_tz', 50)->nullable();
$table->dateTime('end')->nullable();
$table->string('end_tz', 50)->nullable();
$table->string('type', 255);
$table->integer('count', false, true)->default(0);
$table->decimal('amount', 32, 12);
$table->foreign('user_group_id')->references('id')->on('user_groups')->onDelete('cascade');
});
}
}
/**

730
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -42,13 +42,11 @@ function formatLabel(str, maxwidth) {
if (concat.length > maxwidth) {
sections.push(temp);
temp = "";
}
else {
} else {
if (index === (words.length - 1)) {
sections.push(concat);
return;
}
else {
} else {
temp = concat;
return;
}
@@ -62,8 +60,7 @@ function formatLabel(str, maxwidth) {
if (item.length < maxwidth) {
temp = item;
}
else {
} else {
sections.push(item);
}
@@ -98,9 +95,11 @@ var defaultChartOptions = {
ticks: {
callback: function (tickValue) {
"use strict";
if (anonymous) {
return accounting.formatMoney(0);
}
// use first symbol or null:
return accounting.formatMoney(tickValue);
},
beginAtZero: true
}
@@ -112,8 +111,11 @@ var defaultChartOptions = {
callbacks: {
label: function (tooltipItem, data) {
"use strict";
return data.datasets[tooltipItem.datasetIndex].label + ': ' +
accounting.formatMoney(tooltipItem.yLabel, data.datasets[tooltipItem.datasetIndex].currency_symbol);
var string = accounting.formatMoney(tooltipItem.yLabel, data.datasets[tooltipItem.datasetIndex].currency_symbol);
if (anonymous) {
string = accounting.formatMoney(0);
}
return data.datasets[tooltipItem.datasetIndex].label + ': ' + string;
}
}
}
@@ -125,7 +127,11 @@ var pieOptionsWithCurrency = {
label: function (tooltipItem, data) {
"use strict";
var value = data.datasets[0].data[tooltipItem.index];
return data.labels[tooltipItem.index] + ': ' + accounting.formatMoney(value, data.datasets[tooltipItem.datasetIndex].currency_symbol[tooltipItem.index]);
var string = accounting.formatMoney(value, data.datasets[tooltipItem.datasetIndex].currency_symbol[tooltipItem.index]);
if (anonymous) {
string = accounting.formatMoney(0);
}
return data.labels[tooltipItem.index] + ': ' + string;
}
}
},
@@ -139,7 +145,11 @@ var defaultPieOptions = {
label: function (tooltipItem, data) {
"use strict";
var value = data.datasets[0].data[tooltipItem.index];
return data.labels[tooltipItem.index] + ': ' + accounting.formatMoney(value);
var string = accounting.formatMoney(value);
if (anonymous) {
string = accounting.formatMoney(0);
}
return data.labels[tooltipItem.index] + ': ' + string;
}
}
},
@@ -153,7 +163,11 @@ var neutralDefaultPieOptions = {
label: function (tooltipItem, data) {
"use strict";
var value = data.datasets[0].data[tooltipItem.index];
return data.labels[tooltipItem.index] + ': ' + accounting.formatMoney(value, '¤');
var string = accounting.formatMoney(value, '¤');
if(anonymous) {
string = accounting.formatMoney(0);
}
return data.labels[tooltipItem.index] + ': ' + string;
}
}
},

View File

@@ -47,7 +47,6 @@ function parseToLocalDates() {
$(function () {
"use strict";
configAccounting(currencySymbol);
// on submit of logout button:

View File

@@ -17,13 +17,42 @@
* 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/>.
*/
/** global: token, helpPageTitle */
/** global: token, helpPageTitle, anonymous */
$(function () {
"use strict";
$('#help').click(showHelp);
$('#anonymous').click(changeAnonymity)
});
function submitAnonymity(value) {
$.ajax({
url: 'api/v1/preferences/anonymous',
data: JSON.stringify({data: value}),
type: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
},
});
}
function changeAnonymity(e) {
if (anonymous) {
console.log('Will DISABLE.');
submitAnonymity(false);
alert(anonymous_warning_off_txt);
window.location.reload(true);
}
if (!anonymous) {
console.log('Will ENABLE.');
submitAnonymity(true);
alert(anonymous_warning_on_txt);
window.location.reload(true);
}
return false;
}
function showHelp(e) {
"use strict";
var target = $(e.target);

View File

@@ -143,9 +143,19 @@ There is also a [security policy](https://github.com/firefly-iii/firefly-iii/sec
## Support the development of Firefly III
If you like Firefly III and if it helps you save lots of money, why not send me a dime for every dollar saved! 🥳
Firefly III is a side gig. With your sponsorship or support, I can spend more time on Firefly III. So, if you like Firefly III, and if it helps you save lots of money, why not send me a dime for every dollar saved! 🥳
OK that was a joke. If you feel Firefly III made your life better, please consider contributing as a sponsor. Please check out my [Patreon](https://www.patreon.com/jc5) and [GitHub Sponsors](https://github.com/sponsors/JC5) page for more information. You can also [buy me a ☕️ coffee at ko-fi.com](https://ko-fi.com/Q5Q5R4SH1). Thank you for your consideration.
OK, that was a joke. But for real, when you feel Firefly III made your life better, please consider contributing as a sponsor. Please check out my [Patreon](https://www.patreon.com/jc5) and [GitHub Sponsors](https://github.com/sponsors/JC5) page for more information. You can also [buy me a ☕️ coffee at ko-fi.com](https://ko-fi.com/Q5Q5R4SH1) or send something my way using [Liberapay](https://liberapay.com/JC5). Thank you for your consideration.
### Sponsorships
Firefly III is sponsored by LamdaTest. Their support allows me to test Firefly III more easily and introduce even fewer bugs with every release.
<p style="font-size:21px; color:black;">Browser testing via
<a href="https://www.lambdatest.com/?utm_source=fireflyiii&utm_medium=sponsor" target="_blank">
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
</a>
</p>
<!-- END OF SPONSOR TEXT -->

View File

@@ -44,20 +44,29 @@
<div class="box-body no-padding">
<nav v-if="totalPages > 1">
<ul class="pagination">
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.previous')">
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true"
:aria-label="$t('pagination.previous')">
<span class="page-link" aria-hidden="true">&lsaquo;</span>
</li>
<li class="page-item" v-if="1 !== this.page">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)" rel="prev" :aria-label="$t('pagination.next')">&lsaquo;</a>
<a class="page-link"
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)"
rel="prev" :aria-label="$t('pagination.next')">&lsaquo;</a>
</li>
<li v-for="item in this.totalPages" :class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
<li v-for="item in this.totalPages"
:class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
<span v-if="item === page" class="page-link" v-text="item"></span>
<a v-if="item !== page" class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item" v-text="item"></a>
<a v-if="item !== page" class="page-link"
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item"
v-text="item"></a>
</li>
<li v-if="totalPages !== page" class="page-item">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)" rel="next" :aria-label="$t('pagination.next')">&rsaquo;</a>
<a class="page-link"
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)"
rel="next" :aria-label="$t('pagination.next')">&rsaquo;</a>
</li>
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.next')">
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true"
:aria-label="$t('pagination.next')">
<span class="page-link" aria-hidden="true">&rsaquo;</span>
</li>
</ul>
@@ -97,9 +106,11 @@
>
</td>
<td>
<!-- (<span v-text="rate.rate_id"></span>) -->
<input type="number" class="form-control" min="0" step="any" v-model="rate.rate">
</td>
<td>
<!-- (<span v-text="rate.inverse_id"></span>) -->
<input type="number" class="form-control" min="0" step="any" v-model="rate.inverse">
</td>
<td>
@@ -122,20 +133,29 @@
<nav v-if="totalPages > 1">
<ul class="pagination">
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.previous')">
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true"
:aria-label="$t('pagination.previous')">
<span class="page-link" aria-hidden="true">&lsaquo;</span>
</li>
<li class="page-item" v-if="1 !== this.page">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)" rel="prev" :aria-label="$t('pagination.next')">&lsaquo;</a>
<a class="page-link"
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)"
rel="prev" :aria-label="$t('pagination.next')">&lsaquo;</a>
</li>
<li v-for="item in this.totalPages" :class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
<li v-for="item in this.totalPages"
:class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
<span v-if="item === page" class="page-link" v-text="item"></span>
<a v-if="item !== page" class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item" v-text="item"></a>
<a v-if="item !== page" class="page-link"
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item"
v-text="item"></a>
</li>
<li v-if="totalPages !== page" class="page-item">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)" rel="next" :aria-label="$t('pagination.next')">&rsaquo;</a>
<a class="page-link"
:href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)"
rel="next" :aria-label="$t('pagination.next')">&rsaquo;</a>
</li>
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.next')">
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true"
:aria-label="$t('pagination.next')">
<span class="page-link" aria-hidden="true">&rsaquo;</span>
</li>
</ul>
@@ -160,7 +180,8 @@
<label for="ffInput_date" class="col-sm-4 control-label"
v-text="$t('form.date')"></label>
<div class="col-sm-8">
<input class="form-control" type="date" name="date" id="ffInput_date" :disabled="posting"
<input class="form-control" type="date" name="date" id="ffInput_date"
:disabled="posting"
autocomplete="off" spellcheck="false" v-model="newDate">
</div>
</div>
@@ -168,16 +189,19 @@
<label for="ffInput_rate" class="col-sm-4 control-label"
v-text="$t('form.rate')"></label>
<div class="col-sm-8">
<input class="form-control" type="number" name="rate" id="ffInput_rate" :disabled="posting"
<input class="form-control" type="number" name="rate" id="ffInput_rate"
:disabled="posting"
autocomplete="off" spellcheck="false" v-model="newRate" step="any">
<p class="help-block" v-text="$t('firefly.help_rate_form', {from: from_code, to: to_code})">
<p class="help-block"
v-text="$t('firefly.help_rate_form', {from: from_code, to: to_code})">
</p>
</div>
</div>
</div>
<div class="box-footer">
<button type="submit" class="nodisablebutton btn pull-right btn-success" v-text="$t('firefly.save_new_rate')"></button>
<button type="submit" class="nodisablebutton btn pull-right btn-success"
v-text="$t('firefly.save_new_rate')"></button>
</div>
</div>
@@ -217,9 +241,9 @@ export default {
mounted() {
// get from and to code from URL
this.newDate = format(new Date, 'yyyy-MM-dd');
let parts = window.location.href.split('/');
this.from_code = parts[parts.length - 2];
this.to_code = parts[parts.length - 1];
let parts = window.location.pathname.split('/');
this.from_code = parts[parts.length - 2].toUpperCase();
this.to_code = parts[parts.length - 1].toUpperCase();
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
@@ -232,8 +256,8 @@ export default {
this.downloadRates(this.page);
},
methods: {
submitRate: function(e) {
if(e) e.preventDefault();
submitRate: function (e) {
if (e) e.preventDefault();
this.posting = true;
axios.post("./api/v1/exchange-rates", {
@@ -260,33 +284,74 @@ export default {
if (0 === parts.length) {
return;
}
console.log('These are the parts', parts);
if ('' !== this.rates[index].rate) {
//console.log('[a] Rate info is', this.rates[index]);
this.updating = true;
axios.put("./api/v1/exchange-rates/" + this.rates[index].rate_id, {rate: this.rates[index].rate})
.then(() => {
this.updating = false;
});
if (0 === parseInt(this.rates[index].rate_id)) {
console.log('[a] POST, not PUT.');
axios.post('./api/v1/exchange-rates',
{
from: this.from_code,
to: this.to_code,
rate: this.rates[index].rate,
date: this.rates[index].date_field
})
.then(() => {
this.updating = false;
});
}
if (0 !== parseInt(this.rates[index].rate_id)) {
console.log('[a] PUT, not POST.');
axios.put('./api/v1/exchange-rates/' + this.rates[index].rate_id, {rate: this.rates[index].rate})
.then(() => {
this.updating = false;
});
}
}
if ('' !== this.rates[index].inverse) {
//console.log('[b] Rate info is', this.rates[index]);
this.updating = true;
axios.put("./api/v1/exchange-rates/" + this.rates[index].inverse_id, {rate: this.rates[index].inverse})
.then(() => {
this.updating = false;
});
if (0 === parseInt(this.rates[index].inverse_id)) {
console.log('[b] POST, not PUT.');
// post, not put
axios.post('./api/v1/exchange-rates',
{
// remember, this is in reverse.
from: this.to_code,
to: this.from_code,
rate: this.rates[index].inverse,
date: this.rates[index].date_field
})
.then(() => {
this.updating = false;
});
}
if (0 !== parseInt(this.rates[index].inverse_id)) {
console.log('[b] PUT, not POST.');
axios.put('./api/v1/exchange-rates/' + this.rates[index].inverse_id, {rate: this.rates[index].inverse})
.then(() => {
this.updating = false;
});
}
}
},
deleteRate: function (index) {
// console.log(this.rates[index].key);
let parts = this.spliceKey(this.rates[index].key);
if (0 === parts.length) {
return;
}
// console.log(parts);
let rateId = parseInt(this.rates[index].rate_id);
let inverseId = parseInt(this.rates[index].inverse_id);
// delete A to B
axios.delete("./api/v1/exchange-rates/" + parts.from + '/' + parts.to + '/' + format(parts.date, 'yyyy-MM-dd'));
// delete B to A.
axios.delete("./api/v1/exchange-rates/" + parts.to + '/' + parts.from + '/' + format(parts.date, 'yyyy-MM-dd'));
if (rateId > 0) {
axios.delete('./api/v1/exchange-rates/' + rateId);
}
if (inverseId > 0) {
axios.delete('./api/v1/exchange-rates/' + inverseId);
}
this.rates.splice(index, 1);
},
@@ -307,6 +372,7 @@ export default {
};
},
downloadCurrencies: function () {
console.log('Now downloading currencies.');
this.loading = true;
axios.get("./api/v1/currencies/" + this.from_code).then((response) => {
this.from = {
@@ -327,31 +393,36 @@ export default {
downloadRates: function (page) {
this.tempRates = {};
this.loading = true;
axios.get("./api/v1/exchange-rates/" + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => {
console.log('Now downloading rates.', page);
axios.get('./api/v1/exchange-rates/' + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => {
for (let i in response.data.data) {
if (response.data.data.hasOwnProperty(i)) {
console.log('Downloaded entry #' + i);
let current = response.data.data[i];
let date = new Date(current.attributes.date);
let from_code = current.attributes.from_currency_code;
let to_code = current.attributes.to_currency_code;
let from_code = current.attributes.from_currency_code.toUpperCase();
let to_code = current.attributes.to_currency_code.toUpperCase();
let rate = current.attributes.rate;
let inverse = '';
let rate_id = current.id;
let inverse_id = '0';
let key = from_code + '_' + to_code + '_' + format(date, 'yyyy-MM-dd');
// console.log('Key is now "' + key + '"');
console.log('Key is now "' + key + '"');
// perhaps the returned rate is actually the inverse rate.
if (from_code === this.to_code && to_code === this.from_code) {
// console.log('Inverse rate found!');
key = to_code + '_' + from_code + '_' + format(date, 'yyyy-MM-dd');
rate = '';
// new: set rate id to zero.
rate_id = '0';
inverse = current.attributes.rate;
inverse_id = current.id;
// console.log('Key updated to "' + key + '"');
console.log('Key updated to "' + key + '"');
}
if (!this.tempRates.hasOwnProperty(key)) {
console.log('New entry stored');
this.tempRates[key] = {
key: key,
date: date,
@@ -374,6 +445,7 @@ export default {
this.tempRates[key].rate = rate;
this.tempRates[key].rate_id = rate_id;
}
console.log('Found exchange rate #' + this.tempRates[key].rate_id + ' with inverse #' + this.tempRates[key].inverse_id);
}

View File

@@ -35,5 +35,5 @@ return [
'currencies-index' => 'Firefly III supports multiple currencies. Although it defaults to the Euro it can be set to the US Dollar and many other currencies. As you can see a small selection of currencies has been included but you can add your own if you wish to. Changing the default currency will not change the currency of existing transactions however: Firefly III supports the use of multiple currencies at the same time.',
'transactions-index' => 'These expenses, deposits and transfers are not particularly imaginative. They have been generated automatically.',
'piggy-banks-index' => 'As you can see, there are three piggy banks. Use the plus and minus buttons to influence the amount of money in each piggy bank. Click the name of the piggy bank to see the administration for each piggy bank.',
'profile-index' => 'Keep in mind that the demo site resets every four hours. Your access may be revoked at any time. This happens automatically and is not a bug.',
'profile-index' => 'Keep in mind that the demo site resets every four hours. Standard user agents (curl, Postman, wget) are blocked. Your access may be revoked at any time. This happens automatically and is not a bug.',
];

View File

@@ -235,6 +235,8 @@ return [
'advanced_options_explain' => 'Some pages in Firefly III have advanced options hidden behind this button. This page doesn\'t have anything fancy here, but do check out the others!',
'here_be_dragons' => 'Hic sunt dracones',
'bad_date_transaction' => 'Firefly III has detected you have transactions from before the year 1970. Please correct these transactions at your earliest convenience.',
'anonymous_warning_on' => 'For your privacy, all amounts are now displayed as "zero". Warning: text input boxes may still show the original amounts!',
'anonymous_warning_off' => 'Amounts will be visible again. Please be mindful of your surroundings.',
// Webhooks
'webhooks' => 'Webhooks',
@@ -823,6 +825,8 @@ return [
'apply_rule_group_selection' => 'Apply rule group ":title" to a selection of your transactions',
'apply_rule_group_selection_intro' => 'Rule groups like ":title" are normally only applied to new or updated transactions, but you can tell Firefly III to run all the rules in this group on a selection of your existing transactions. This can be useful when you have updated a group of rules and you need the changes to be applied to all of your other transactions.',
'applied_rule_group_selection' => 'Rule group ":title" has been applied to your selection.',
'rule_run_after_creation' => 'If you check this box, you get the opportunity to run the rule after it has been created.',
'rule_run_after_edit' => 'If you check this box, you get the opportunity to run the rule after it has been updated.',
// actions and triggers
'rule_trigger_store_journal' => 'When a transaction is created',

View File

@@ -66,6 +66,7 @@ return [
'opening_balance' => 'Opening balance',
'tag_mode' => 'Tag mode',
'virtual_balance' => 'Virtual balance',
'run_after_form' => 'Run this rule',

View File

@@ -24,6 +24,7 @@
declare(strict_types=1);
return [
'invalid_account_list' => 'Invalid account type list',
'limit_exists' => 'There is already a budget limit (amount) for this budget and currency in the given period.',
'invalid_sort_instruction' => 'The sort instruction is invalid for an object of type ":object".',
'invalid_sort_instruction_index' => 'The sort instruction at index #:index is invalid for an object of type ":object".',
@@ -32,6 +33,7 @@ return [
'webhook_account_info' => 'Cannot deliver account information for budget related webhooks.',
'webhook_transaction_info' => 'Cannot deliver transaction information for budget related webhooks.',
'invalid_account_type' => 'A piggy bank can only be linked to asset accounts and liabilities',
'unique_currency_code' => 'This currency code is already in use',
'invalid_account_currency' => 'This account does not use the currency you have selected',
'current_amount_too_much' => 'The combined amount in "current_amount" cannot exceed the "target_amount".',
'filter_must_be_in' => 'Filter ":filter" must be one of: :values',

View File

@@ -90,15 +90,15 @@
var iAmOwed = '{{ 'i_am_owed_amount'|_|escape('js') }}';
var iOwe = '{{ 'i_owe_amount'|_|escape('js') }}';
</script>
<script type="text/javascript" src="v1/js/lib/modernizr-custom.js?v={{ FF_VERSION }}"
<script type="text/javascript" src="v1/js/lib/modernizr-custom.js?v={{ FF_BUILD_TIME }}"
nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/lib/jquery-ui.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/ff/accounts/create.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/lib/jquery-ui.min.js?v={{ FF_BUILD_TIME }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/ff/accounts/create.js?v={{ FF_BUILD_TIME }}" nonce="{{ JS_NONCE }}"></script>
{% endblock %}
{% block styles %}
<link href="v1/css/jquery-ui/jquery-ui.structure.min.css?v={{ FF_VERSION }}" type="text/css" rel="stylesheet"
<link href="v1/css/jquery-ui/jquery-ui.structure.min.css?v={{ FF_BUILD_TIME }}" type="text/css" rel="stylesheet"
media="all" nonce="{{ JS_NONCE }}">
<link href="v1/css/jquery-ui/jquery-ui.theme.min.css?v={{ FF_VERSION }}" type="text/css" rel="stylesheet"
<link href="v1/css/jquery-ui/jquery-ui.theme.min.css?v={{ FF_BUILD_TIME }}" type="text/css" rel="stylesheet"
media="all" nonce="{{ JS_NONCE }}">
{% endblock %}

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