Compare commits

...

61 Commits

Author SHA1 Message Date
github-actions[bot]
c8c4816fe8 Merge pull request #11948 from firefly-iii/release-1773486711
🤖 Automatically merge the PR into the develop branch.
2026-03-14 12:12:01 +01:00
JC5
aa57252b11 🤖 Auto commit for release 'develop' on 2026-03-14 2026-03-14 12:11:52 +01:00
James Cole
58e4c26a87 Fix call to budget repos. 2026-03-14 12:05:45 +01:00
github-actions[bot]
ac323f11c4 Merge pull request #11946 from firefly-iii/release-1773474241
🤖 Automatically merge the PR into the develop branch.
2026-03-14 08:44:10 +01:00
JC5
a907f9b2f7 🤖 Auto commit for release 'develop' on 2026-03-14 2026-03-14 08:44:01 +01:00
James Cole
8abd2a6604 Add text about AI reports. 2026-03-14 08:36:39 +01:00
James Cole
0780390ff6 Update changelog. 2026-03-14 07:46:47 +01:00
James Cole
b9d1ed28a5 Update dev mode settings. 2026-03-14 07:31:16 +01:00
James Cole
b8ebcdf1a8 Remove CSS, only chartJS remains 2026-03-14 06:40:23 +01:00
James Cole
ac8dbbff6c Remove CSS and unused files. 2026-03-14 06:25:11 +01:00
James Cole
fea89c5231 Remove and replace inline styles. 2026-03-14 06:16:53 +01:00
James Cole
654f2ee489 Remove inline CSS 2026-03-14 06:02:40 +01:00
James Cole
5c18624cf9 Fix https://github.com/firefly-iii/firefly-iii/issues/11944 2026-03-14 05:37:30 +01:00
James Cole
27ba8e842a Remove CSS 2026-03-13 20:47:42 +01:00
James Cole
e504ee204a Remove styles. 2026-03-13 20:44:51 +01:00
James Cole
a3a332643c Replace styles with classes. 2026-03-13 20:35:39 +01:00
James Cole
464a89f305 Remove lots of style attributes. 2026-03-13 20:22:50 +01:00
James Cole
062c2323e3 Clean up and expand css styles. 2026-03-13 19:49:56 +01:00
James Cole
a37f995872 Can be returned directly. 2026-03-13 17:36:03 +01:00
James Cole
a5b6315cb8 Clean up transaction link code. 2026-03-13 17:35:39 +01:00
github-actions[bot]
ff568653c8 Merge pull request #11940 from firefly-iii/release-1773385883
🤖 Automatically merge the PR into the develop branch.
2026-03-13 08:11:30 +01:00
JC5
21447a9b2f 🤖 Auto commit for release 'develop' on 2026-03-13 2026-03-13 08:11:23 +01:00
James Cole
238bfc819e Catch a null pointer. 2026-03-13 08:05:04 +01:00
James Cole
3fab4668fc Move copyright. 2026-03-13 04:14:46 +01:00
James Cole
190050d6cf Rate limit mail message. 2026-03-13 04:12:32 +01:00
James Cole
45d623e0c1 Fix some linting issues 2026-03-13 04:05:38 +01:00
github-actions[bot]
93fe8dbf42 Merge pull request #11938 from firefly-iii/release-1773370546
🤖 Automatically merge the PR into the develop branch.
2026-03-13 03:55:56 +01:00
JC5
63c49f740f 🤖 Auto commit for release 'develop' on 2026-03-13 2026-03-13 03:55:47 +01:00
James Cole
bc23bc0173 Fix reference to IP. 2026-03-13 03:50:02 +01:00
James Cole
1611cb3819 Add link to Firefly III in emails 2026-03-13 03:40:07 +01:00
Sander Dorigo
c520e79b85 Expand changelog 2026-03-12 08:42:26 +01:00
Sander Dorigo
51e005f305 Finally fix often reported enum issue in rule engine 2026-03-12 08:41:15 +01:00
James Cole
133449640d Fix phpstan issues by adding properties. 2026-03-09 20:56:09 +01:00
James Cole
c5a126eb61 Merge branch 'main' into develop 2026-03-09 20:39:56 +01:00
James Cole
4222d8ffdd Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Http/Controllers/Transaction/MassController.php
2026-03-09 20:39:35 +01:00
James Cole
28ff0a8423 Fix a bunch of phpstan issues. 2026-03-09 20:38:58 +01:00
James Cole
4c0e599b01 Merge pull request #11920 from firefly-iii/dependabot/github_actions/crazy-max/ghaction-import-gpg-7 2026-03-09 06:39:06 +01:00
dependabot[bot]
10d2137723 Bump crazy-max/ghaction-import-gpg from 6 to 7
Bumps [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) from 6 to 7.
- [Release notes](https://github.com/crazy-max/ghaction-import-gpg/releases)
- [Commits](https://github.com/crazy-max/ghaction-import-gpg/compare/v6...v7)

---
updated-dependencies:
- dependency-name: crazy-max/ghaction-import-gpg
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 03:53:55 +00:00
github-actions[bot]
f9b7149fc7 Merge pull request #11919 from firefly-iii/release-1773028359
🤖 Automatically merge the PR into the develop branch.
2026-03-09 04:52:46 +01:00
JC5
7c3fb7a95a 🤖 Auto commit for release 'develop' on 2026-03-09 2026-03-09 04:52:39 +01:00
James Cole
91b7ee06d8 Fix moar phpstan issues. 2026-03-08 17:44:19 +01:00
James Cole
84ea19d14c Fix a bunch of phpstan errors. 2026-03-08 17:08:51 +01:00
James Cole
9950f79a6b Merge branch 'main' into develop 2026-03-08 11:57:21 +01:00
James Cole
e3df7675d3 Fix https://github.com/firefly-iii/firefly-iii/issues/11916 2026-03-08 11:56:53 +01:00
James Cole
15094097bc Update various templates. 2026-03-07 13:42:11 +01:00
github-actions[bot]
a07dc4dbc8 Merge pull request #11904 from firefly-iii/release-1772875617
🤖 Automatically merge the PR into the develop branch.
2026-03-07 10:27:06 +01:00
JC5
c86562554b 🤖 Auto commit for release 'develop' on 2026-03-07 2026-03-07 10:26:58 +01:00
James Cole
19b548a417 Fix null type issues. 2026-03-07 10:20:06 +01:00
James Cole
71698b36e2 Fix various phpstan issues. 2026-03-07 10:17:07 +01:00
github-actions[bot]
f65ee4d419 Merge pull request #11901 from firefly-iii/release-1772861474
🤖 Automatically merge the PR into the develop branch.
2026-03-07 06:31:23 +01:00
JC5
535fd9777a 🤖 Auto commit for release 'develop' on 2026-03-07 2026-03-07 06:31:14 +01:00
James Cole
5d1fde9cf7 Clean up more errors. 2026-03-07 06:26:08 +01:00
James Cole
922f1e7c1a Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2026-03-07 06:25:45 +01:00
github-actions[bot]
ef5c35c04d Merge pull request #11900 from firefly-iii/release-1772860900
🤖 Automatically merge the PR into the develop branch.
2026-03-07 06:21:47 +01:00
JC5
4dfbdc644c 🤖 Auto commit for release 'develop' on 2026-03-07 2026-03-07 06:21:40 +01:00
James Cole
4a3f45e125 Add empty array 2026-03-07 06:15:55 +01:00
github-actions[bot]
a08f776ffa Merge pull request #11897 from firefly-iii/release-1772828319
🤖 Automatically merge the PR into the develop branch.
2026-03-06 21:18:48 +01:00
JC5
e246c1f4b7 🤖 Auto commit for release 'develop' on 2026-03-06 2026-03-06 21:18:39 +01:00
github-actions[bot]
f2d1e8e184 Merge pull request #11896 from firefly-iii/release-1772825547
🤖 Automatically merge the PR into the develop branch.
2026-03-06 20:32:37 +01:00
JC5
19d8f46f24 🤖 Auto commit for release 'develop' on 2026-03-06 2026-03-06 20:32:27 +01:00
James Cole
9ac991edd7 Fix phpstan issues. 2026-03-06 20:25:07 +01:00
538 changed files with 2654 additions and 1975 deletions

View File

@@ -1264,16 +1264,16 @@
},
{
"name": "symfony/console",
"version": "v8.0.6",
"version": "v8.0.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "488285876e807a4777f074041d8bb508623419fa"
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/488285876e807a4777f074041d8bb508623419fa",
"reference": "488285876e807a4777f074041d8bb508623419fa",
"url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
"shasum": ""
},
"require": {
@@ -1330,7 +1330,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v8.0.6"
"source": "https://github.com/symfony/console/tree/v8.0.7"
},
"funding": [
{
@@ -1350,7 +1350,7 @@
"type": "tidelift"
}
],
"time": "2026-02-25T16:59:43+00:00"
"time": "2026-03-06T14:06:22+00:00"
},
{
"name": "symfony/deprecation-contracts",

View File

@@ -33,35 +33,14 @@ parameters:
- Illuminate\Database\Eloquent\Model
reportUnmatchedIgnoredErrors: true
ignoreErrors:
# these are actually interesting but not right now:
- identifier: greater.alwaysTrue
- identifier: function.alreadyNarrowedType
- identifier: booleanNot.alwaysTrue
- identifier: property.phpDocType
- identifier: nullCoalesce.offset
- identifier: nullCoalesce.variable
- identifier: larastan.noUnnecessaryCollectionCall
- identifier: varTag.differentVariable
- identifier: identical.alwaysTrue
- identifier: assign.propertyReadOnly
- identifier: varTag.nativeType
- identifier: property.onlyWritten
- identifier: parameter.phpDocType
- identifier: property.dynamicName
- identifier: property.unusedType
- identifier: staticMethod.deprecated
# ignore everything but things that BREAK
- identifier: property.deprecated
- identifier: method.deprecated
- identifier: cast.useless
- identifier: parameter.deprecatedClass
- identifier: method.deprecatedClass
- identifier: argument.type
- identifier: return.type
- identifier: assign.propertyType
- identifier: return.unusedType
- identifier: return.phpDocType
# all errors below I will (probably) never fix.
- identifier: property.unusedType # one false positive
- identifier: varTag.nativeType # dont even know what im supposed to fix.
- identifier: method.notFound # way too many false positives
- identifier: catch.neverThrown # plenty of errors that are thrown undocumented
- identifier: staticMethod.dynamicName # dont care
@@ -74,9 +53,6 @@ parameters:
# - '#expects view-string, string given#'
# - "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
- identifier: missingType.generics # not interesting enough to fix.
-
identifier: larastan.noEnvCallsOutsideOfConfig
path: ../app/Console/Commands/System/CreatesDatabase.php
- identifier: missingType.iterableValue # not interesting enough to fix.
- identifier: varTag.type # needs a custom extension for every repository, not gonna happen.
# - '#Dynamic call to static method Illuminate#'

25
.github/security.md vendored
View File

@@ -3,13 +3,12 @@
Firefly III is an application to manage your personal finances. As such, the developer has adopted this security
disclosure and response policy to ensure that critical issues are responsibly handled.
## Supported Versions
## Supported versions
Only the latest Firefly III release is maintained. Applicable fixes, including security fixes, will not backported to
older release branches. Please refer to [releases.md](https://github.com/firefly-iii/firefly-iii/blob/main/releases.md)
for details.
older release branches. Please refer to [releases.md](https://github.com/firefly-iii/firefly-iii/blob/main/releases.md) for details.
## Reporting a Vulnerability - Private Disclosure Process
## Reporting a vulnerability - private disclosure process
Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be
reported to Firefly III privately, to minimize attacks against current users of Firefly III before they are fixed.
@@ -28,7 +27,7 @@ within 3 business days, including a detailed plan to investigate the issue and a
the meantime. Do not report non-security-impacting bugs through this channel.
Use [GitHub issues](https://github.com/firefly-iii/firefly-iii/issues/new/choose) instead.
### Proposed Email Content
### Proposed email content
Provide a descriptive subject line and in the body of the email include the following information:
@@ -47,7 +46,7 @@ Provide a descriptive subject line and in the body of the email include the foll
* When you know of or suspect a potential vulnerability on another project that is used by Firefly III. For example
Firefly III has a dependency on Docker, MySQL, etc.
## Patch, Release, and Disclosure
## Patch, release, and disclosure
The Firefly III developer will respond to vulnerability reports as follows:
@@ -75,7 +74,7 @@ The Firefly III developer will respond to vulnerability reports as follows:
8. Once the fix is confirmed, the developer will patch the vulnerability in the next patch or minor release. Upon
release of the patched version of Firefly III, we will follow the **Public Disclosure Process**.
### Public Disclosure Process
### Public disclosure process
The developer publishes a public [advisory](https://github.com/firefly-iii/firefly-iii/security/advisories) to the
Firefly III community via GitHub. In most cases, additional communication via Mastodon, Gitter and other channels will
@@ -97,6 +96,18 @@ III to provide a hardened Firefly III environment. We will not act on any securi
safe defaults. Over time, we will work towards improved safe-by-default configuration, taking into account backwards
compatibility.
## Security scanning through automated means
There is some additional guidance for security vulnerabilities or suspected security vulnerabilities that have been
found with the full or partial support of AI coding agents, large language models and other code-scanning tools. Many of
such reports the developer of Firefly III receives are not applicable. This takes time away from responding to
actual security vulnerabilities or suspected security vulnerabilities. If you use automated means to find these in
the Firefly III code base, please take care to:
1. Manually validate the results before you submit a report,
2. explain how the vulnerability can actually be abused by a nefarious third party, and
3. try to limit the verbosity of your report.
## Credits
This security policy is based on [Harbor](https://github.com/goharbor/harbor)'s security policy.

View File

@@ -33,7 +33,7 @@ jobs:
with:
fetch-depth: 0
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
uses: crazy-max/ghaction-import-gpg@v7
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}

View File

@@ -80,16 +80,16 @@ final class AccountController extends Controller
public function accounts(AutocompleteApiRequest $request): JsonResponse
{
// Log::debug('Before All.');
['types' => $types, 'query' => $query, 'date' => $date, 'limit' => $limit] = $request->attributes->all();
['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 = [];
$result = $this->repository->searchAccount((string) $query, $types, $limit);
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
$return = [];
$result = $this->repository->searchAccount((string) $query, $types, $limit);
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
/** @var Account $account */
foreach ($result as $account) {

View File

@@ -63,7 +63,7 @@ final class BillController extends Controller
public function bills(AutocompleteApiRequest $request): JsonResponse
{
$result = $this->repository->searchBill($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(static fn (Bill $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
$filtered = $result->map(static fn (Bill $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
return response()->api($filtered->toArray());
}

View File

@@ -63,7 +63,7 @@ final class BudgetController extends Controller
public function budgets(AutocompleteApiRequest $request): JsonResponse
{
$result = $this->repository->searchBudget($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(static fn (Budget $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
$filtered = $result->map(static fn (Budget $item): array => ['id' => (string) $item->id, 'name' => $item->name, 'active' => $item->active]);
return response()->api($filtered->toArray());
}

View File

@@ -63,7 +63,7 @@ final class CategoryController extends Controller
public function categories(AutocompleteApiRequest $request): JsonResponse
{
$result = $this->repository->searchCategory($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(static fn (Category $item): array => ['id' => (string) $item->id, 'name' => $item->name]);
$filtered = $result->map(static fn (Category $item): array => ['id' => (string) $item->id, 'name' => $item->name]);
return response()->api($filtered->toArray());
}

View File

@@ -67,7 +67,7 @@ final class ObjectGroupController extends Controller
/** @var ObjectGroup $objectGroup */
foreach ($result as $objectGroup) {
$return[] = ['id' => (string) $objectGroup->id, 'name' => $objectGroup->title, 'title' => $objectGroup->title];
$return[] = ['id' => (string) $objectGroup->id, 'name' => $objectGroup->title, 'title' => $objectGroup->title];
}
return response()->api($return);

View File

@@ -63,7 +63,7 @@ final class TagController extends Controller
/** @var Tag $tag */
foreach ($result as $tag) {
$array[] = ['id' => (string) $tag->id, 'name' => $tag->tag, 'tag' => $tag->tag];
$array[] = ['id' => (string) $tag->id, 'name' => $tag->tag, 'tag' => $tag->tag];
}
return response()->api($array);

View File

@@ -62,7 +62,7 @@ final class TransactionTypeController extends Controller
/** @var TransactionType $type */
foreach ($types as $type) {
// different key for consistency.
$array[] = ['id' => (string) $type->id, 'name' => $type->type, 'type' => $type->type];
$array[] = ['id' => (string) $type->id, 'name' => $type->type, 'type' => $type->type];
}
return response()->api($array);

View File

@@ -220,7 +220,7 @@ final class BudgetController extends Controller
'end_date' => $row['end'],
'yAxisID' => 0,
'type' => 'bar',
'entries' => ['budgeted' => $row['budgeted'], 'spent' => $row['spent'], 'left' => $row['left'], 'overspent' => $row['overspent']],
'entries' => ['budgeted' => $row['budgeted'], 'spent' => $row['spent'], 'left' => $row['left'], 'overspent' => $row['overspent']],
'pc_entries' => [
'budgeted' => $row['pc_budgeted'],
'spent' => $row['pc_spent'],

View File

@@ -153,8 +153,8 @@ final class CategoryController extends Controller
'end_date' => $end->toAtomString(),
'yAxisID' => 0,
'type' => 'bar',
'entries' => ['spent' => '0', 'earned' => '0'],
'pc_entries' => ['spent' => '0', 'earned' => '0'],
'entries' => ['spent' => '0', 'earned' => '0'],
'pc_entries' => ['spent' => '0', 'earned' => '0'],
];
// add monies

View File

@@ -63,6 +63,8 @@ abstract class Controller extends BaseController
use ValidatesRequests;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [];
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json';
@@ -169,6 +171,9 @@ abstract class Controller extends BaseController
return $manager->createData($resource)->toArray();
}
/**
* @deprecated
*/
#[Deprecated(message: <<<'TXT'
use Request classes
Method to grab all parameters from the URL
@@ -222,7 +227,8 @@ abstract class Controller extends BaseController
$value = min(max(1, $value), 2 ** 16);
$bag->set($integer, $value);
}
if (null === $value && 'limit' === $integer && auth()->check()) {
// && 'limit' === $integer
if (null === $value && auth()->check()) {
// set default for user:
/** @var User $user */
$user = auth()->user();

View File

@@ -185,6 +185,8 @@ final class DestroyController extends Controller
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgetRepository->destroyAll();
$abRepository->cleanup();
}
private function destroyCategories(): void

View File

@@ -70,21 +70,21 @@ final class ListController extends Controller
public function attachments(PaginationRequest $request, Account $account): JsonResponse
{
$manager = $this->getManager();
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
$collection = $this->repository->getAttachments($account);
$manager = $this->getManager();
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
$collection = $this->repository->getAttachments($account);
$count = $collection->count();
$attachments = $collection->slice($offset, $limit);
$count = $collection->count();
$attachments = $collection->slice($offset, $limit);
// make paginator:
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $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 = app(AttachmentTransformer::class);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
@@ -93,31 +93,31 @@ final class ListController extends Controller
public function piggyBanks(PaginationRequest $request, Account $account): JsonResponse
{
// create some objects:
$manager = $this->getManager();
$manager = $this->getManager();
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
['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($offset, $limit);
$collection = $this->repository->getPiggyBanks($account);
$count = $collection->count();
$piggyBanks = $collection->slice($offset, $limit);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new PiggyBankEnrichment();
$admin = auth()->user();
$enrichment = new PiggyBankEnrichment();
$enrichment->setUser($admin);
$piggyBanks = $enrichment->enrich($piggyBanks);
$piggyBanks = $enrichment->enrich($piggyBanks);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $limit, $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 = app(PiggyBankTransformer::class);
// $transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
@@ -128,16 +128,16 @@ final class ListController extends Controller
*/
public function transactions(PaginationDateRangeRequest $request, Account $account): JsonResponse
{
['limit' => $limit, 'page' => $page, 'start' => $start, 'end' => $end, 'type' => $type] = $request->attributes->all();
$types = $this->mapTransactionTypes($type ?? 'default');
$manager = $this->getManager();
['limit' => $limit, 'page' => $page, 'start' => $start, 'end' => $end, 'type' => $type] = $request->attributes->all();
$types = $this->mapTransactionTypes($type ?? 'default');
$manager = $this->getManager();
/** @var User $admin */
$admin = auth()->user();
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setUser($admin)->setAccounts(new Collection()->push($account))->withAPIInformation()->setLimit($limit)->setPage($page)->setTypes($types);
if (null !== $start) {
$collector->setStart($start);
@@ -146,18 +146,18 @@ final class ListController extends Controller
$collector->setEnd($end);
}
$paginator = $collector->getPaginatedGroups();
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.accounts.transactions', [$account->id]).$this->buildParams());
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);
$transformer = app(TransactionGroupTransformer::class);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -124,22 +124,22 @@ final class ShowController extends Controller
// get list of accounts. Count it and split it.
$this->repository->resetAccountOrder();
$account->refresh();
$manager = $this->getManager();
['start' => $start, 'end' => $end, 'date' => $date] = $request->attributes->all();
$manager = $this->getManager();
['start' => $start, 'end' => $end, 'date' => $date] = $request->attributes->all();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setDate($date);
$enrichment->setStart($start);
$enrichment->setEnd($end);
$enrichment->setUser($admin);
$account = $enrichment->enrichSingle($account);
$account = $enrichment->enrichSingle($account);
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
$transformer = app(AccountTransformer::class);
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}

View File

@@ -121,7 +121,7 @@ final class ShowController extends Controller
*/
public function index(PaginationRequest $request): JsonResponse
{
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
if (true === auth()->user()->hasRole('demo')) {
Log::channel('audit')->warning(sprintf('Demo user tries to access attachment API in %s', __METHOD__));
@@ -129,21 +129,21 @@ final class ShowController extends Controller
throw new NotFoundHttpException();
}
$manager = $this->getManager();
$manager = $this->getManager();
// get list of attachments. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$attachments = $collection->slice($offset, $limit);
$collection = $this->repository->get();
$count = $collection->count();
$attachments = $collection->slice($offset, $limit);
// make paginator:
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
$paginator->setPath(route('api.v1.attachments.index').$this->buildParams());
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer = app(AttachmentTransformer::class);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -68,29 +68,29 @@ final class ShowController extends Controller
*/
public function index(PaginationDateRangeRequest $request): JsonResponse
{
$manager = $this->getManager();
['limit' => $limit, 'offset' => $offset, 'page' => $page, 'start' => $start, 'end' => $end] = $request->attributes->all();
$manager = $this->getManager();
['limit' => $limit, 'offset' => $offset, 'page' => $page, 'start' => $start, 'end' => $end] = $request->attributes->all();
// get list of available budgets. Count it and split it.
$collection = $this->abRepository->getAvailableBudgetsByDate($start, $end);
$count = $collection->count();
$availableBudgets = $collection->slice($offset, $limit);
$collection = $this->abRepository->getAvailableBudgetsByDate($start, $end);
$count = $collection->count();
$availableBudgets = $collection->slice($offset, $limit);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AvailableBudgetEnrichment();
$admin = auth()->user();
$enrichment = new AvailableBudgetEnrichment();
$enrichment->setUser($admin);
$availableBudgets = $enrichment->enrich($availableBudgets);
$availableBudgets = $enrichment->enrich($availableBudgets);
// make paginator:
$paginator = new LengthAwarePaginator($availableBudgets, $count, $limit, $page);
$paginator = new LengthAwarePaginator($availableBudgets, $count, $limit, $page);
$paginator->setPath(route('api.v1.available-budgets.index').$this->buildParams());
/** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class);
$transformer = app(AvailableBudgetTransformer::class);
$resource = new FractalCollection($availableBudgets, $transformer, 'available_budgets');
$resource = new FractalCollection($availableBudgets, $transformer, 'available_budgets');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -72,21 +72,21 @@ final class ListController extends Controller
*/
public function attachments(PaginationRequest $request, Bill $bill): JsonResponse
{
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
$manager = $this->getManager();
$collection = $this->repository->getAttachments($bill);
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
$manager = $this->getManager();
$collection = $this->repository->getAttachments($bill);
$count = $collection->count();
$attachments = $collection->slice($offset, $limit);
$count = $collection->count();
$attachments = $collection->slice($offset, $limit);
// make paginator:
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
$paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
$paginator->setPath(route('api.v1.bills.attachments', [$bill->id]).$this->buildParams());
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
$transformer = app(AttachmentTransformer::class);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
@@ -100,20 +100,20 @@ final class ListController extends Controller
*/
public function rules(PaginationRequest $request, Bill $bill): JsonResponse
{
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
['limit' => $limit, 'offset' => $offset, 'page' => $page] = $request->attributes->all();
$manager = $this->getManager();
$collection = $this->repository->getRulesForBill($bill);
$count = $collection->count();
$rules = $collection->slice($offset, $limit);
$manager = $this->getManager();
$collection = $this->repository->getRulesForBill($bill);
$count = $collection->count();
$rules = $collection->slice($offset, $limit);
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $limit, $page);
$paginator = new LengthAwarePaginator($rules, $count, $limit, $page);
$paginator->setPath(route('api.v1.bills.rules', [$bill->id]).$this->buildParams());
/** @var RuleTransformer $transformer */
$transformer = app(RuleTransformer::class);
$resource = new FractalCollection($rules, $transformer, 'rules');
$transformer = app(RuleTransformer::class);
$resource = new FractalCollection($rules, $transformer, 'rules');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
@@ -127,16 +127,16 @@ final class ListController extends Controller
*/
public function transactions(PaginationDateRangeRequest $request, Bill $bill): JsonResponse
{
['limit' => $limit, 'page' => $page, 'types' => $types, 'start' => $start, 'end' => $end] = $request->attributes->all();
['limit' => $limit, 'page' => $page, 'types' => $types, 'start' => $start, 'end' => $end] = $request->attributes->all();
$manager = $this->getManager();
$manager = $this->getManager();
/** @var User $admin */
$admin = auth()->user();
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector
->setUser($admin)
// include source + destination account name and type.
@@ -159,18 +159,18 @@ final class ListController extends Controller
}
// get paginator.
$paginator = $collector->getPaginatedGroups();
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.bills.transactions', [$bill->id]).$this->buildParams());
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);
$transformer = app(TransactionGroupTransformer::class);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -67,28 +67,28 @@ final class ShowController extends Controller
*/
public function index(PaginationDateRangeRequest $request): JsonResponse
{
['limit' => $limit, 'offset' => $offset, 'start' => $start, 'end' => $end, 'page' => $page] = $request->attributes->all();
['limit' => $limit, 'offset' => $offset, 'start' => $start, 'end' => $end, 'page' => $page] = $request->attributes->all();
$this->repository->correctOrder();
$bills = $this->repository->getBills();
$manager = $this->getManager();
$count = $bills->count();
$bills = $bills->slice($offset, $limit);
$paginator = new LengthAwarePaginator($bills, $count, $limit, $page);
$bills = $this->repository->getBills();
$manager = $this->getManager();
$count = $bills->count();
$bills = $bills->slice($offset, $limit);
$paginator = new LengthAwarePaginator($bills, $count, $limit, $page);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new SubscriptionEnrichment();
$admin = auth()->user();
$enrichment = new SubscriptionEnrichment();
$enrichment->setUser($admin);
$enrichment->setStart($start);
$enrichment->setEnd($end);
$bills = $enrichment->enrich($bills);
$bills = $enrichment->enrich($bills);
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer = app(BillTransformer::class);
$resource = new FractalCollection($bills, $transformer, 'bills');
$resource = new FractalCollection($bills, $transformer, 'bills');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
@@ -102,23 +102,23 @@ final class ShowController extends Controller
*/
public function show(DateRangeRequest $request, Bill $bill): JsonResponse
{
['start' => $start, 'end' => $end] = $request->attributes->all();
['start' => $start, 'end' => $end] = $request->attributes->all();
$manager = $this->getManager();
$manager = $this->getManager();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new SubscriptionEnrichment();
$admin = auth()->user();
$enrichment = new SubscriptionEnrichment();
$enrichment->setUser($admin);
$enrichment->setStart($start);
$enrichment->setEnd($end);
$bill = $enrichment->enrichSingle($bill);
$bill = $enrichment->enrichSingle($bill);
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer = app(BillTransformer::class);
$resource = new Item($bill, $transformer, 'bills');
$resource = new Item($bill, $transformer, 'bills');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}

View File

@@ -83,7 +83,6 @@ final class StoreController extends Controller
/** @var BillTransformer $transformer */
$transformer = app(BillTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($bill, $transformer, 'bills');

View File

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\BudgetLimit;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
@@ -118,12 +118,12 @@ final class ShowController extends Controller
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
*/
public function indexAll(SameDateRequest $request): JsonResponse
public function indexAll(DateRangeRequest $request): JsonResponse
{
$manager = $this->getManager();
$manager->parseIncludes('budget');
$pageSize = $this->parameters->get('limit');
$collection = $this->blRepository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end'));
$collection = $this->blRepository->getAllBudgetLimits($request->attributes->get('start'), $request->attributes->get('end'));
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));

View File

@@ -1,10 +1,8 @@
<?php
declare(strict_types=1);
/*
* TriggerController.php
* Copyright (c) 2025 james@firefly-iii.org
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,10 +20,12 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Generic\SingleDateRequest;
use FireflyIII\Api\V1\Requests\DateRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Jobs\CreateRecurringTransactions;
use FireflyIII\Models\Recurrence;
@@ -59,12 +59,12 @@ final class TriggerController extends Controller
});
}
public function trigger(SingleDateRequest $request, Recurrence $recurrence): JsonResponse
public function trigger(DateRequest $request, Recurrence $recurrence): JsonResponse
{
// find recurrence occurrence for this date and trigger it.
// grab the date from the last time the recurrence fired:
$backupDate = $recurrence->latest_date;
$date = $request->getDate();
$date = $request->attributes->get('date');
// fire the recurring cron job on the given date, then post-date the created transaction.
Log::info(sprintf('Trigger: will now fire recurring cron job task for date "%s".', $date->format('Y-m-d H:i:s')));

View File

@@ -78,15 +78,15 @@ final class TriggerController extends Controller
// overrule the rule(s) if necessary.
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
}
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
}
if (array_key_exists('accounts', $parameters) && '' !== $parameters['accounts']) {
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
}
// file the rule(s)
@@ -98,7 +98,7 @@ final class TriggerController extends Controller
$enrichment->setUser($rule->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rules.test', [$rule->id]).$this->buildParams());
// resulting list is presented as JSON thing.
@@ -132,15 +132,15 @@ final class TriggerController extends Controller
// overrule the rule(s) if necessary.
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
}
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
}
if (array_key_exists('accounts', $parameters) && is_array($parameters['accounts']) && count($parameters['accounts']) > 0) {
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
}
// fire the rule(s)

View File

@@ -85,15 +85,15 @@ final class TriggerController extends Controller
// overrule the rule(s) if necessary.
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
}
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
}
if (array_key_exists('accounts', $parameters) && '' !== $parameters['accounts']) {
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
}
// file the rule(s)
@@ -105,7 +105,7 @@ final class TriggerController extends Controller
$enrichment->setUser($group->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rule-groups.test', [$group->id]).$this->buildParams());
// resulting list is presented as JSON thing.
@@ -146,15 +146,15 @@ final class TriggerController extends Controller
// overrule the rule(s) if necessary.
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
}
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
// add a range:
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
}
if (array_key_exists('accounts', $parameters) && is_array($parameters['accounts']) && count($parameters['accounts']) > 0) {
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
}
// file the rule(s)

View File

@@ -48,6 +48,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
final class UpdateController extends Controller
{
private TransactionGroupRepositoryInterface $groupRepository;
protected array $acceptedRoles = [];
/**
* TransactionController constructor.

View File

@@ -32,6 +32,7 @@ use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class DestroyController
@@ -71,6 +72,12 @@ final class DestroyController extends Controller
if (false === $linkType->editable) {
throw new FireflyException('200020: Link type cannot be changed.');
}
if (false === auth()->user()->hasRole('owner')) {
Log::channel('audit')->warning('Non-owner user tries to delete a link type.');
response()->json([], 401);
}
$this->repository->destroy($linkType);
Preferences::mark();

View File

@@ -52,12 +52,12 @@ final class IndexController extends Controller
public function index(PaginationRequest $request): JsonResponse
{
$administrations = $this->repository->get();
['page' => $page, 'limit' => $limit, 'offset' => $offset] = $request->attributes->all();
$count = $administrations->count();
$administrations = $administrations->slice($offset, $limit);
$paginator = new LengthAwarePaginator($administrations, $count, $limit, $page);
$transformer = new UserGroupTransformer();
$administrations = $this->repository->get();
['page' => $page, 'limit' => $limit, 'offset' => $offset] = $request->attributes->all();
$count = $administrations->count();
$administrations = $administrations->slice($offset, $limit);
$paginator = new LengthAwarePaginator($administrations, $count, $limit, $page);
$transformer = new UserGroupTransformer();
return response()->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))->header('Content-Type', self::CONTENT_TYPE);
}

View File

@@ -81,6 +81,7 @@ final class BasicController extends Controller
$this->accountRepository->setUser($user);
$this->abRepository->setUser($user);
$this->opsRepository->setUser($user);
$this->abRepository->cleanup();
return $next($request);
});
@@ -89,20 +90,20 @@ final class BasicController extends Controller
public function basic(BasicRequest $request): JsonResponse
{
// parameters for boxes:
['start' => $start, 'end' => $end, 'code' => $code] = $request->attributes->all();
['start' => $start, 'end' => $end, 'code' => $code] = $request->attributes->all();
// balance information:
$balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getSubscriptionInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($end);
$balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getSubscriptionInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($end);
// $balanceData = [];
// $billData = [];
// $spentData = [];
// $netWorthData = [];
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys
$return = [];
$return = [];
foreach ($total as $entry) {
if ('' === $code || $code === $entry['currency_code']) {
$return[$entry['key']] = $entry;

View File

@@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
/*
* BatchController.php
* Copyright (c) 2026 james@firefly-iii.org
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\System;
use FireflyIII\Api\V1\Controllers\Controller;

View File

@@ -32,9 +32,11 @@ use RuntimeException;
abstract class AggregateFormRequest extends ApiRequest
{
/**
* @var ApiRequest[]
* @var Request[]
*/
protected array $requests = [];
protected array $requests = [];
protected array $acceptedRoles = [];
#[Override]
public function initialize(

View File

@@ -32,7 +32,9 @@ class ApiRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected string $required = '';
protected array $acceptedRoles = [];
protected string $required = '';
public function handleConfig(array $config): void
{

View File

@@ -1,10 +1,8 @@
<?php
declare(strict_types=1);
/*
* AutocompleteApiRequest.php
* Copyright (c) 2025 james@firefly-iii.org
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Autocomplete;
use FireflyIII\Api\V1\Requests\AggregateFormRequest;

View File

@@ -39,6 +39,8 @@ class AutocompleteRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getData(): array
{
$types = $this->convertString('types');
@@ -52,7 +54,7 @@ class AutocompleteRequest extends FormRequest
$date = $this->getCarbonDate('date') ?? today(config('app.timezone'));
return ['types' => $array, 'query' => $this->convertString('query'), 'date' => $date->endOfDay()];
return ['types' => $array, 'query' => $this->convertString('query'), 'date' => $date->endOfDay()];
}
public function rules(): array

View File

@@ -39,9 +39,11 @@ class MoveTransactionsRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getAll(): array
{
return ['original_account' => $this->convertInteger('original_account'), 'destination_account' => $this->convertInteger('destination_account')];
return ['original_account' => $this->convertInteger('original_account'), 'destination_account' => $this->convertInteger('destination_account')];
}
/**

View File

@@ -45,6 +45,8 @@ class TransactionRequest extends FormRequest
use ConvertsDataTypes;
use ValidatesBulkTransactionQuery;
protected array $acceptedRoles = [];
public function getAll(): array
{
$data = [];

View File

@@ -36,6 +36,8 @@ class DestroyRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
@@ -54,6 +56,6 @@ class DestroyRequest extends FormRequest
.',accounts,asset_accounts,expense_accounts,revenue_accounts,liabilities,transactions,withdrawals,deposits,transfers'
.',not_assets_liabilities';
return ['objects' => sprintf('required|max:255|min:1|string|in:%s', $valid), 'unused' => 'in:true,false'];
return ['objects' => sprintf('required|max:255|min:1|string|in:%s', $valid), 'unused' => 'in:true,false'];
}
}

View File

@@ -39,6 +39,8 @@ class ExportRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getAll(): array
{
$result = [
@@ -70,6 +72,6 @@ class ExportRequest extends FormRequest
*/
public function rules(): array
{
return ['type' => 'in:csv', 'accounts' => 'min:1|max:32768', 'start' => 'date|before:end', 'end' => 'date|after:start'];
return ['type' => 'in:csv', 'accounts' => 'min:1|max:32768', 'start' => 'date|before:end', 'end' => 'date|after:start'];
}
}

View File

@@ -40,12 +40,14 @@ class SameDateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
}
/**
@@ -53,6 +55,6 @@ class SameDateRequest extends FormRequest
*/
public function rules(): array
{
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
}
}

View File

@@ -41,6 +41,8 @@ class SingleDateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -45,6 +45,8 @@ class GenericRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
private Collection $accounts;
private Collection $bills;
private Collection $budgets;
@@ -56,7 +58,7 @@ class GenericRequest extends FormRequest
*/
public function getAll(): array
{
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
}
public function getAssetAccounts(): Collection
@@ -167,7 +169,7 @@ class GenericRequest extends FormRequest
$this->bills = new Collection();
$this->tags = new Collection();
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
return ['start' => 'required|date', 'end' => 'required|date|after_or_equal:start'];
}
private function parseAccounts(): void

View File

@@ -45,7 +45,7 @@ class AccountTypeApiRequest extends ApiRequest
}
$type = $this->convertString('type', 'all');
$this->attributes->add(['type' => $type, 'types' => $this->mapAccountTypes($type)]);
$this->attributes->add(['type' => $type, 'types' => $this->mapAccountTypes($type)]);
});
}
}

View File

@@ -43,6 +43,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getAllAccountData(): array
{
$active = true;

View File

@@ -46,6 +46,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getUpdateData(): array
{
$fields = [

View File

@@ -37,6 +37,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -37,6 +37,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -40,6 +40,8 @@ class Request extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -42,6 +42,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -41,6 +41,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -42,6 +42,8 @@ class StoreRequest extends FormRequest
use ConvertsDataTypes;
use ValidatesAutoBudgetRequest;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -43,6 +43,8 @@ class UpdateRequest extends FormRequest
use ConvertsDataTypes;
use ValidatesAutoBudgetRequest;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
@@ -65,7 +67,7 @@ class UpdateRequest extends FormRequest
];
$allData = $this->getAllData($fields);
if (array_key_exists('auto_budget_type', $allData)) {
$types = ['none' => 0, 'reset' => 1, 'rollover' => 2, 'adjusted' => 3];
$types = ['none' => 0, 'reset' => 1, 'rollover' => 2, 'adjusted' => 3];
$allData['auto_budget_type'] = $types[$allData['auto_budget_type']] ?? 0;
}

View File

@@ -45,6 +45,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -41,6 +41,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -36,12 +36,14 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
return ['name' => $this->convertString('name'), 'notes' => $this->stringWithNewlines('notes')];
return ['name' => $this->convertString('name'), 'notes' => $this->stringWithNewlines('notes')];
}
/**

View File

@@ -37,12 +37,14 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
$fields = ['name' => ['name', 'convertString'], 'notes' => ['notes', 'stringWithNewlines']];
$fields = ['name' => ['name', 'convertString'], 'notes' => ['notes', 'stringWithNewlines']];
return $this->getAllData($fields);
}

View File

@@ -34,6 +34,8 @@ class DestroyRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getDate(): ?Carbon
{
return $this->getCarbonDate('date');

View File

@@ -36,6 +36,8 @@ class StoreByCurrenciesRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getAll(): array
{
return $this->all();

View File

@@ -37,12 +37,14 @@ class StoreByDateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* @return array<string, mixed>
*/
public function getAll(): array
{
return ['from' => $this->get('from'), 'rates' => $this->get('rates', [])];
return ['from' => $this->get('from'), 'rates' => $this->get('rates', [])];
}
public function getFromCurrency(): TransactionCurrency
@@ -57,7 +59,7 @@ class StoreByDateRequest extends FormRequest
*/
public function rules(): array
{
return ['from' => 'required|exists:transaction_currencies,code', 'rates' => 'required|array', 'rates.*' => 'required|numeric|min:0.0000000001'];
return ['from' => 'required|exists:transaction_currencies,code', 'rates' => 'required|array', 'rates.*' => 'required|numeric|min:0.0000000001'];
}
public function withValidator(Validator $validator): void

View File

@@ -36,6 +36,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getDate(): ?Carbon
{
return $this->getCarbonDate('date');

View File

@@ -34,6 +34,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getDate(): ?Carbon
{
return $this->getCarbonDate('date');

View File

@@ -37,6 +37,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getUpdateData(): array
{
$fields = ['title' => ['title', 'convertString'], 'order' => ['order', 'convertInteger']];

View File

@@ -42,6 +42,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -40,6 +40,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -49,6 +49,8 @@ class StoreRequest extends FormRequest
use RecurrenceValidation;
use TransactionValidation;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
@@ -67,7 +69,7 @@ class StoreRequest extends FormRequest
];
$recurrence = $this->getAllData($fields);
return ['recurrence' => $recurrence, 'transactions' => $this->getTransactionData(), 'repetitions' => $this->getRepetitionData()];
return ['recurrence' => $recurrence, 'transactions' => $this->getTransactionData(), 'repetitions' => $this->getRepetitionData()];
}
/**

View File

@@ -50,6 +50,8 @@ class UpdateRequest extends FormRequest
use RecurrenceValidation;
use TransactionValidation;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -42,6 +42,8 @@ class StoreRequest extends FormRequest
use ConvertsDataTypes;
use GetRuleConfiguration;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -37,9 +37,11 @@ class TestRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getTestParameters(): array
{
return ['page' => $this->getPage(), 'start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
return ['page' => $this->getPage(), 'start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
}
public function rules(): array

View File

@@ -37,9 +37,11 @@ class TriggerRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getTriggerParameters(): array
{
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
}
public function rules(): array

View File

@@ -43,6 +43,8 @@ class UpdateRequest extends FormRequest
use ConvertsDataTypes;
use GetRuleConfiguration;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -35,6 +35,8 @@ class ValidateExpressionRequest extends FormRequest
{
use ChecksLogin;
protected array $acceptedRoles = [];
public function rules(): array
{
return ['expression' => ['required', new IsValidActionExpression()]];

View File

@@ -37,13 +37,15 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
$active = true;
$order = 31337;
$order = 31_337;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}

View File

@@ -37,9 +37,11 @@ class TestRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getTestParameters(): array
{
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
}
public function rules(): array

View File

@@ -37,14 +37,16 @@ class TriggerRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getTriggerParameters(): array
{
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
return ['start' => $this->getDate('start'), 'end' => $this->getDate('end'), 'accounts' => $this->getAccounts()];
}
public function rules(): array
{
return ['start' => 'date|after:1970-01-02|before:2038-01-17', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17'];
return ['start' => 'date|after:1970-01-02|before:2038-01-17', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17'];
}
private function getAccounts(): array

View File

@@ -38,6 +38,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -39,6 +39,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -40,13 +40,15 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
// This is the way.
$fields = ['tag' => ['tag', 'convertString'], 'date' => ['date', 'date'], 'description' => ['description', 'convertString']];
$fields = ['tag' => ['tag', 'convertString'], 'date' => ['date', 'date'], 'description' => ['description', 'convertString']];
$data = $this->getAllData($fields);
return $this->appendLocationData($data, null);

View File

@@ -54,6 +54,8 @@ class StoreRequest extends FormRequest
use GroupValidation;
use TransactionValidation;
protected array $acceptedRoles = [];
/**
* Get all data. Is pretty complex because of all the ??-statements.
*/

View File

@@ -50,6 +50,8 @@ class UpdateRequest extends FormRequest
use GroupValidation;
use TransactionValidation;
protected array $acceptedRoles = [];
private array $arrayFields;
private array $booleanFields;
private array $dateFields;

View File

@@ -37,6 +37,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -38,6 +38,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -41,6 +41,8 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -41,6 +41,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/

View File

@@ -36,12 +36,14 @@ class StoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
}
/**

View File

@@ -38,12 +38,14 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Get all data from the request.
*/
public function getAll(): array
{
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
return ['name' => $this->convertString('name'), 'outward' => $this->convertString('outward'), 'inward' => $this->convertString('inward')];
}
/**

View File

@@ -36,6 +36,8 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getData(): array
{
$fields = [

View File

@@ -43,9 +43,11 @@ class CreateRequest extends FormRequest
use ConvertsDataTypes;
use ValidatesWebhooks;
protected array $acceptedRoles = [];
public function getData(): array
{
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
$triggers = $this->get('triggers', []);
$responses = $this->get('responses', []);
$deliveries = $this->get('deliveries', []);

View File

@@ -43,9 +43,11 @@ class UpdateRequest extends FormRequest
use ConvertsDataTypes;
use ValidatesWebhooks;
protected array $acceptedRoles = [];
public function getData(): array
{
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
$fields = ['title' => ['title', 'convertString'], 'active' => ['active', 'boolean'], 'url' => ['url', 'convertString']];
$triggers = $this->get('triggers', []);
$responses = $this->get('responses', []);

View File

@@ -48,7 +48,7 @@ class CronRequest extends FormRequest
*/
public function getAll(): array
{
$data = ['force' => false, 'date' => today(config('app.timezone'))];
$data = ['force' => false, 'date' => today(config('app.timezone'))];
if ($this->has('force')) {
$data['force'] = $this->boolean('force');
}
@@ -68,6 +68,6 @@ class CronRequest extends FormRequest
*/
public function rules(): array
{
return ['force' => 'in:true,false', 'date' => 'nullable|date|after:1970-01-02|before:2038-01-17'];
return ['force' => 'in:true,false', 'date' => 'nullable|date|after:1970-01-02|before:2038-01-17'];
}
}

View File

@@ -37,7 +37,9 @@ class UpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
private array $booleans = [
protected array $acceptedRoles = [];
private array $booleans = [
'configuration.is_demo_site',
'configuration.single_user_mode',
'configuration.enable_exchange_rates',
@@ -46,7 +48,7 @@ class UpdateRequest extends FormRequest
'configuration.enable_external_rates',
'configuration.allow_webhooks',
];
private array $integers = ['configuration.permission_update_check', 'configuration.last_update_check'];
private array $integers = ['configuration.permission_update_check', 'configuration.last_update_check'];
/**
* Get all data from the request.

View File

@@ -37,6 +37,8 @@ class UserStoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Logged in + owner
*/

View File

@@ -40,6 +40,8 @@ class UserUpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
/**
* Logged in + owner
*/

View File

@@ -36,6 +36,8 @@ class PreferenceStoreRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getAll(): array
{
$array = ['name' => $this->convertString('name'), 'data' => $this->get('data')];

View File

@@ -36,6 +36,8 @@ class PreferenceUpdateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
protected array $acceptedRoles = [];
public function getAll(): array
{
$array = ['name' => $this->convertString('name'), 'data' => $this->get('data')];

View File

@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
@@ -82,7 +83,7 @@ class ConvertsDatesToUTC extends Command
return;
}
$this->friendlyInfo(sprintf('Converting field "%s" of model "%s" to UTC.', $field, $shortModel));
$items->each(static function ($item) use ($field, $timezoneField): void {
$items->each(static function (Model $item) use ($field, $timezoneField): void {
$date = Carbon::parse($item->{$field}, $item->{$timezoneField});
$date->setTimezone('UTC');
$item->{$field} = $date->format('Y-m-d H:i:s');

View File

@@ -229,12 +229,24 @@ class CorrectsAccountTypes extends Command
private function getDestinationTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '>', 0);
/** @var null|Transaction $res */
$res = $journal->transactions->firstWhere('amount', '>', 0);
if (null === $res) {
throw new FireflyException('Could not find transaction.');
}
return $res;
}
private function getSourceTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '<', 0);
/** @var null|Transaction $res */
$res = $journal->transactions->firstWhere('amount', '<', 0);
if (null === $res) {
throw new FireflyException('Could not find transaction.');
}
return $res;
}
private function giveNewDestinationAccount(TransactionJournal $journal, Account $newDestination): void

View File

@@ -69,10 +69,6 @@ class CorrectsInvertedBudgetLimits extends Command
$budgetLimit->saveQuietly();
}
if ($set->count() > 0) {
// FIXME here be a available budget event.
}
if (1 === $set->count()) {
$this->friendlyInfo('Corrected one budget limit to have the right start/end dates.');

View File

@@ -66,7 +66,7 @@ class CreatesGroupMemberships extends Command
->first()
;
if (null === $membership) {
GroupMembership::create(['user_id' => $user->id, 'user_role_id' => $userRole->id, 'user_group_id' => $userGroup->id]);
GroupMembership::create(['user_id' => $user->id, 'user_role_id' => $userRole->id, 'user_group_id' => $userGroup->id]);
}
if (null === $user->user_group_id) {
$user->user_group_id = $userGroup->id;

View File

@@ -29,6 +29,8 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
@@ -92,6 +94,18 @@ class RemovesLinksToDeletedObjects extends Command
if (count($deletedCategories) > 0) {
$this->cleanupCategories($deletedCategories);
}
// count and clean up available budgets in currencies with no budget limits.
// this is not entirely the place for it but OK.
/** @var AvailableBudgetRepositoryInterface $repository */
$repository = app(AvailableBudgetRepositoryInterface::class);
/** @var User $user */
foreach (User::get() as $user) {
$repository->setUser($user);
$repository->cleanup();
}
$this->friendlyNeutral('Validated links to deleted objects.');
}

View File

@@ -75,7 +75,10 @@ class RollbacksSingleMigration extends Command
}
if ($res) {
DB::table('migrations')->where('id', (int) $entry->id)->delete();
DB::table('migrations')
->where('id', (int) $entry->id)
->delete()
;
$this->friendlyInfo(sprintf('Database migration #%d ("%s") is deleted.', $entry->id, $entry->migration));
$this->friendlyLine('');
$this->friendlyLine('Try running "php artisan migrate" now.');

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