Compare commits

...

52 Commits

Author SHA1 Message Date
github-actions[bot]
19dece287e Merge pull request #11949 from firefly-iii/release-1773489415
🤖 Automatically merge the PR into the develop branch.
2026-03-14 12:57:02 +01:00
JC5
897e1f773e 🤖 Auto commit for release 'develop' on 2026-03-14 2026-03-14 12:56:55 +01:00
James Cole
5788e18d6d Fix inline CSS. 2026-03-14 12:39:33 +01:00
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
465 changed files with 2374 additions and 1860 deletions

View File

@@ -33,29 +33,14 @@ parameters:
- Illuminate\Database\Eloquent\Model
reportUnmatchedIgnoredErrors: true
ignoreErrors:
# these are actually interesting but not right now:
- 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
@@ -68,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

@@ -171,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
@@ -224,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,7 +32,7 @@ use RuntimeException;
abstract class AggregateFormRequest extends ApiRequest
{
/**
* @var ApiRequest[]
* @var Request[]
*/
protected array $requests = [];

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

@@ -54,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

@@ -43,7 +43,7 @@ class MoveTransactionsRequest extends FormRequest
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

@@ -56,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

@@ -72,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

@@ -47,7 +47,7 @@ class SameDateRequest extends FormRequest
*/
public function getAll(): array
{
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
return ['start' => $this->getCarbonDate('start'), 'end' => $this->getCarbonDate('end')];
}
/**
@@ -55,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

@@ -58,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
@@ -169,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

@@ -67,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

@@ -43,7 +43,7 @@ class StoreRequest extends FormRequest
*/
public function getAll(): array
{
return ['name' => $this->convertString('name'), 'notes' => $this->stringWithNewlines('notes')];
return ['name' => $this->convertString('name'), 'notes' => $this->stringWithNewlines('notes')];
}
/**

View File

@@ -44,7 +44,7 @@ class UpdateRequest extends FormRequest
*/
public function getAll(): array
{
$fields = ['name' => ['name', 'convertString'], 'notes' => ['notes', 'stringWithNewlines']];
$fields = ['name' => ['name', 'convertString'], 'notes' => ['notes', 'stringWithNewlines']];
return $this->getAllData($fields);
}

View File

@@ -44,7 +44,7 @@ class StoreByDateRequest extends FormRequest
*/
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
@@ -59,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

@@ -69,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

@@ -41,7 +41,7 @@ class TestRequest extends FormRequest
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

@@ -41,7 +41,7 @@ class TriggerRequest extends FormRequest
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

@@ -45,7 +45,7 @@ class StoreRequest extends FormRequest
public function getAll(): array
{
$active = true;
$order = 31337;
$order = 31_337;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}

View File

@@ -41,7 +41,7 @@ class TestRequest extends FormRequest
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

@@ -41,12 +41,12 @@ class TriggerRequest extends FormRequest
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

@@ -48,7 +48,7 @@ class UpdateRequest extends FormRequest
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

@@ -43,7 +43,7 @@ class StoreRequest extends FormRequest
*/
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

@@ -45,7 +45,7 @@ class UpdateRequest extends FormRequest
*/
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

@@ -47,7 +47,7 @@ class CreateRequest extends FormRequest
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

@@ -47,7 +47,7 @@ class UpdateRequest extends FormRequest
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

@@ -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

@@ -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.');

View File

@@ -0,0 +1,79 @@
<?php
/*
* SendTestEmail.php
* Copyright (c) 2026 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\Console\Commands;
use FireflyIII\Events\Test\OwnerTestsNotificationChannel;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Console\Command;
class SendTestEmail extends Command
{
use ShowsFriendlyMessages;
use VerifiesAccessToken;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:send-test-email
{--user=1 : The user ID.}
{--token= : The user\'s access token.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send test email';
/**
* Execute the console command.
*/
public function handle(): int
{
$user = $this->getUser();
if (!$user->hasRole('owner')) {
$this->friendlyError((string) trans('firefly.must_be_owner'));
return Command::FAILURE;
}
/** @var int $lastNotification */
$lastNotification = FireflyConfig::get('last_test_notification', 123)->data;
if ((time() - $lastNotification) < 120) {
$this->friendlyError((string) trans('firefly.test_rate_limited'));
return Command::FAILURE;
}
$owner = new OwnerNotifiable();
event(new OwnerTestsNotificationChannel('email', $owner));
FireflyConfig::set('last_test_notification', time());
return Command::SUCCESS;
}
}

View File

@@ -54,10 +54,10 @@ class CreatesDatabase extends Command
}
// try to set up a raw connection:
$exists = false;
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', env('DB_HOST'), env('DB_PORT'));
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', config('database.connections.mysql.host'), config('database.connections.mysql.port'));
if ('' !== (string) env('DB_SOCKET')) {
$dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', env('DB_SOCKET'));
if ('' !== (string) config('database.connections.mysql.unix_socket')) {
$dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', config('database.connections.mysql.unix_socket'));
}
$this->friendlyLine(sprintf('DSN is %s', $dsn));
@@ -69,7 +69,7 @@ class CreatesDatabase extends Command
// when it fails, display error
try {
$pdo = new PDO($dsn, (string) env('DB_USERNAME'), (string) env('DB_PASSWORD'), $options);
$pdo = new PDO($dsn, (string) config('database.connections.mysql.username'), (string) config('database.connections.mysql.password'), $options);
} catch (PDOException $e) {
$this->friendlyError(sprintf('Error when connecting to DB: %s', $e->getMessage()));
@@ -83,19 +83,19 @@ class CreatesDatabase extends Command
// slightly more complex but less error-prone.
foreach ($stmt as $row) {
$name = $row['Database'] ?? false;
if ($name === env('DB_DATABASE')) {
if ($name === config('database.connections.mysql.database')) {
$exists = true;
}
}
if (false === $exists) {
$this->friendlyError(sprintf('Database "%s" does not exist.', env('DB_DATABASE')));
$this->friendlyError(sprintf('Database "%s" does not exist.', config('database.connections.mysql.database')));
// try to create it.
$pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', env('DB_DATABASE')));
$this->friendlyInfo(sprintf('Created database "%s"', env('DB_DATABASE')));
$pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', config('database.connections.mysql.database')));
$this->friendlyInfo(sprintf('Created database "%s"', config('database.connections.mysql.database')));
}
if ($exists) {
$this->friendlyInfo(sprintf('Database "%s" exists.', env('DB_DATABASE')));
$this->friendlyInfo(sprintf('Database "%s" exists.', config('database.connections.mysql.database')));
}
return 0;

View File

@@ -56,7 +56,7 @@ class CreatesFirstUser extends Command
return 1;
}
$data = ['blocked' => false, 'blocked_code' => null, 'email' => $this->argument('email'), 'role' => 'owner'];
$data = ['blocked' => false, 'blocked_code' => null, 'email' => $this->argument('email'), 'role' => 'owner'];
$password = Str::random(24);
$user = $this->repository->store($data);
$user->password = Hash::make($password);

View File

@@ -78,7 +78,7 @@ class ForcesMigrations extends Command
sleep(2);
Schema::dropIfExists('migrations');
$this->friendlyLine('Re-run all migrations...');
Artisan::call('migrate', ['--seed' => true, '--force' => true]);
Artisan::call('migrate', ['--seed' => true, '--force' => true]);
sleep(2);
$this->friendlyLine('');
$this->friendlyWarning('There is a good chance you just saw a lot of error messages.');

View File

@@ -121,11 +121,11 @@ class ApplyRules extends Command
$filterAccountList[] = $account->id;
}
$list = implode(',', $filterAccountList);
$ruleEngine->addOperator(['type' => 'account_id', 'value' => $list]);
$ruleEngine->addOperator(['type' => 'account_id', 'value' => $list]);
// add the date as a filter:
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $this->startDate->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $this->endDate->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $this->startDate->format('Y-m-d')]);
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $this->endDate->format('Y-m-d')]);
// start running rules.
$this->friendlyLine(sprintf('Will apply %d rule(s) to your transaction(s).', $count));

View File

@@ -84,7 +84,7 @@ class ChecksForUpdates extends Command
}
// if running develop, slightly different message.
if (str_contains($version, 'develop')) {
$this->friendlyInfo(trans('firefly.update_current_dev_older', ['version' => $version, 'new_version' => $info->getNewVersion()]));
$this->friendlyInfo(trans('firefly.update_current_dev_older', ['version' => $version, 'new_version' => $info->getNewVersion()]));
return Command::SUCCESS;
}

View File

@@ -35,7 +35,7 @@ trait VerifiesDatabaseConnectionTrait
{
$loops = 30;
$loop = 0;
$queries = ['pgsql' => 'SELECT * FROM pg_catalog.pg_tables;', 'sqlite' => 'SELECT name FROM sqlite_schema;', 'mysql' => 'SHOW TABLES;'];
$queries = ['pgsql' => 'SELECT * FROM pg_catalog.pg_tables;', 'sqlite' => 'SELECT name FROM sqlite_schema;', 'mysql' => 'SHOW TABLES;'];
$default = config('database.default');
if (!array_key_exists($default, $queries)) {
$this->friendlyWarning(sprintf('Cannot validate database connection for "%s"', $default));

View File

@@ -64,10 +64,6 @@ class RemovesDatabaseDecryption extends Command
'journal_links' => ['comment'],
];
/**
* @var string $table
* @var array $fields
*/
foreach ($tables as $table => $fields) {
$this->decryptTable($table, $fields);
}

View File

@@ -107,7 +107,10 @@ class RepairsPostgresSequences extends Command
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
$nextId = DB::table($tableToCheck)
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
->first()
;
if (null === $nextId) {
$this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck));
@@ -117,7 +120,10 @@ class RepairsPostgresSequences extends Command
if ($nextId->nextval < $highestId->max) {
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
$nextId = DB::table($tableToCheck)
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
->first()
;
if ($nextId->nextval > $highestId->max) {
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
}

View File

@@ -107,7 +107,7 @@ class UpgradesAccountCurrencies extends Command
// both 0? set to default currency:
if (0 === $accountCurrency && 0 === $obCurrency) {
AccountMeta::where('account_id', $account->id)->where('name', 'currency_id')->forceDelete();
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
$this->friendlyInfo(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $currency->code));
++$this->count;
@@ -116,7 +116,7 @@ class UpgradesAccountCurrencies extends Command
// account is set to 0, opening balance is not?
if (0 === $accountCurrency && $obCurrency > 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
$this->friendlyInfo(sprintf('Account #%d ("%s") now has a currency setting (#%d).', $account->id, $account->name, $obCurrency));
++$this->count;

View File

@@ -113,17 +113,17 @@ class UpgradesBillsToRules extends Command
'title' => (string) trans('firefly.rule_for_bill_title', ['name' => $bill->name], $languageString),
'description' => (string) trans('firefly.rule_for_bill_description', ['name' => $bill->name], $languageString),
'trigger' => 'store-journal',
'triggers' => [['type' => 'description_contains', 'value' => $match]],
'actions' => [['type' => 'link_to_bill', 'value' => $bill->name]],
'triggers' => [['type' => 'description_contains', 'value' => $match]],
'actions' => [['type' => 'link_to_bill', 'value' => $bill->name]],
];
// two triggers or one, depends on bill content:
if ($bill->amount_max === $bill->amount_min) {
$newRule['triggers'][] = ['type' => 'amount_exactly', 'value' => $bill->amount_min];
$newRule['triggers'][] = ['type' => 'amount_exactly', 'value' => $bill->amount_min];
}
if ($bill->amount_max !== $bill->amount_min) {
$newRule['triggers'][] = ['type' => 'amount_less', 'value' => $bill->amount_max];
$newRule['triggers'][] = ['type' => 'amount_more', 'value' => $bill->amount_min];
$newRule['triggers'][] = ['type' => 'amount_less', 'value' => $bill->amount_max];
$newRule['triggers'][] = ['type' => 'amount_more', 'value' => $bill->amount_min];
}
$this->ruleRepository->store($newRule);

View File

@@ -95,7 +95,7 @@ class UpgradesDatabase extends Command
private function callInitialCommands(): void
{
$this->call('firefly-iii:verify-database-connection');
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
$this->call('upgrade:600-pgsql-sequences');
$this->call('upgrade:480-decrypt-all');
}

View File

@@ -94,7 +94,7 @@ class UpgradesRecurrenceMetaData extends Command
$value = json_encode($array, JSON_THROW_ON_ERROR);
}
RecurrenceTransactionMeta::create(['rt_id' => $firstTransaction->id, 'name' => $meta->name, 'value' => $value]);
RecurrenceTransactionMeta::create(['rt_id' => $firstTransaction->id, 'name' => $meta->name, 'value' => $value]);
$meta->forceDelete();
return 1;

View File

@@ -94,6 +94,7 @@ class UpgradesToGroups extends Command
return $amount && $identifier;
});
/** @var null|Transaction */
return $set->first();
}

View File

@@ -106,17 +106,20 @@ class UpgradesVariousCurrencyInformation extends Command
break;
case TransactionTypeEnum::WITHDRAWAL->value:
/** @var null|Transaction $lead */
$lead = $journal->transactions()->where('amount', '<', 0)->first();
break;
case TransactionTypeEnum::DEPOSIT->value:
/** @var null|Transaction $lead */
$lead = $journal->transactions()->where('amount', '>', 0)->first();
break;
case TransactionTypeEnum::OPENING_BALANCE->value:
// whichever isn't an initial balance account:
/** @var null|Transaction $lead */
$lead = $journal
->transactions()
->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
@@ -129,6 +132,7 @@ class UpgradesVariousCurrencyInformation extends Command
case TransactionTypeEnum::RECONCILIATION->value:
// whichever isn't the reconciliation account:
/** @var null|Transaction $lead */
$lead = $journal
->transactions()
->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')

View File

@@ -117,40 +117,40 @@ class Handler extends ExceptionHandler
// JSON error:
Log::debug('Return JSON not found error.');
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
}
if ($e instanceof AuthorizationException && $expectsJson) {
// somehow Laravel handler does not catch this:
Log::debug('Return JSON unauthorized error.');
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthorizationException'], 401);
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthorizationException'], 401);
}
if ($e instanceof AuthenticationException && $expectsJson) {
// somehow Laravel handler does not catch this:
Log::debug('Return JSON unauthenticated error.');
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401);
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401);
}
if ($e instanceof OAuthServerException && $expectsJson) {
Log::debug('Return JSON OAuthServerException.');
// somehow Laravel handler does not catch this:
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
}
if ($e instanceof BadRequestHttpException) {
Log::debug('Return JSON BadRequestHttpException.');
return response()->json(['message' => $e->getMessage(), 'exception' => 'HttpException'], 400);
return response()->json(['message' => $e->getMessage(), 'exception' => 'HttpException'], 400);
}
if ($e instanceof BadHttpHeaderException) {
// is always API exception.
Log::debug('Return JSON BadHttpHeaderException.');
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadHttpHeaderException'], $e->statusCode);
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadHttpHeaderException'], $e->statusCode);
}
if (($e instanceof ValidationException || $e instanceof NumberFormatException) && $expectsJson) {
$errorCode = 422;
@@ -197,14 +197,14 @@ class Handler extends ExceptionHandler
Log::debug('Return Firefly III database exception view.');
$isDebug = config('app.debug');
return response()->view('errors.DatabaseException', ['exception' => $e, 'debug' => $isDebug], 500);
return response()->view('errors.DatabaseException', ['exception' => $e, 'debug' => $isDebug], 500);
}
if ($e instanceof FireflyException || $e instanceof ErrorException || $e instanceof OAuthServerException) {
Log::debug('Return Firefly III error view.');
$isDebug = config('app.debug');
return response()->view('errors.FireflyException', ['exception' => $e, 'debug' => $isDebug], 500);
return response()->view('errors.FireflyException', ['exception' => $e, 'debug' => $isDebug], 500);
}
Log::debug(sprintf('Error "%s" has no Firefly III treatment, parent will handle.', $e::class));
@@ -228,7 +228,7 @@ class Handler extends ExceptionHandler
return;
}
$userData = ['id' => 0, 'email' => 'unknown@example.com'];
$userData = ['id' => 0, 'email' => 'unknown@example.com'];
if (auth()->check()) {
$userData['id'] = auth()->user()->id;
$userData['email'] = auth()->user()->email;

View File

@@ -219,7 +219,7 @@ class AccountFactory
'user_group_id' => $this->user->user_group_id,
'account_type_id' => $type->id,
'name' => $data['name'],
'order' => 25000,
'order' => 25_000,
'virtual_balance' => $virtualBalance,
'active' => $active,
'iban' => $data['iban'],

View File

@@ -53,7 +53,7 @@ class AccountMetaFactory
}
// if $data has field and $entry is null, create new one:
if (null === $entry) {
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
}
// if $data has field and $entry is not null, update $entry:

View File

@@ -75,7 +75,7 @@ class CategoryFactory
}
try {
return Category::create(['user_id' => $this->user->id, 'user_group_id' => $this->user->user_group_id, 'name' => $categoryName]);
return Category::create(['user_id' => $this->user->id, 'user_group_id' => $this->user->user_group_id, 'name' => $categoryName]);
} catch (QueryException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());

View File

@@ -159,7 +159,7 @@ class PiggyBankFactory
}
// no amount set, use previous amount
$toBeLinked[$account->id] = ['current_amount' => $toBeLinked[$account->id]['current_amount']];
$toBeLinked[$account->id] = ['current_amount' => $toBeLinked[$account->id]['current_amount'] ?? '0'];
Log::debug(sprintf('[b] Will link account #%d with amount %s', $account->id, $toBeLinked[$account->id]['current_amount']));
// create event:
@@ -246,7 +246,7 @@ class PiggyBankFactory
$piggyBankData['target_date_tz'] = $piggyBankData['target_date']?->format('e');
$piggyBankData['account_id'] = null;
$piggyBankData['transaction_currency_id'] = $this->getCurrency($data)->id;
$piggyBankData['order'] = 131337;
$piggyBankData['order'] = 131_337;
try {
/** @var PiggyBank $piggyBank */

View File

@@ -188,7 +188,7 @@ class TransactionJournalFactory
protected function storeMeta(TransactionJournal $journal, array $data, string $field): void
{
$set = ['journal' => $journal, 'name' => $field, 'data' => (string) ($data[$field] ?? '')];
$set = ['journal' => $journal, 'name' => $field, 'data' => (string) ($data[$field] ?? '')];
if (array_key_exists($field, $data) && $data[$field] instanceof Carbon) {
$data[$field]->setTimezone(config('app.timezone'));
Log::debug(sprintf('%s Date: %s (%s)', $field, $data[$field], $data[$field]->timezone->getName()));

View File

@@ -39,7 +39,7 @@ class ChartJsGenerator implements GeneratorInterface
*/
public function multiCurrencyPieChart(array $data): array
{
$chartData = ['datasets' => [0 => []], 'labels' => []];
$chartData = ['datasets' => [0 => []], 'labels' => []];
$amounts = array_column($data, 'amount');
$next = next($amounts);
@@ -117,7 +117,7 @@ class ChartJsGenerator implements GeneratorInterface
unset($first, $labels);
foreach ($data as $set) {
$currentSet = ['label' => $set['label'] ?? '(no label)', 'type' => $set['type'] ?? 'line', 'data' => array_values($set['entries'])];
$currentSet = ['label' => $set['label'] ?? '(no label)', 'type' => $set['type'] ?? 'line', 'data' => array_values($set['entries'])];
if (array_key_exists('yAxisID', $set)) {
$currentSet['yAxisID'] = $set['yAxisID'];
}
@@ -143,7 +143,7 @@ class ChartJsGenerator implements GeneratorInterface
*/
public function pieChart(array $data): array
{
$chartData = ['datasets' => [0 => []], 'labels' => []];
$chartData = ['datasets' => [0 => []], 'labels' => []];
// sort by value, keep keys.
// different sort when values are positive and when they're negative.
@@ -178,7 +178,7 @@ class ChartJsGenerator implements GeneratorInterface
return [
'count' => 1,
'labels' => array_keys($data), // take ALL labels from the first set.
'datasets' => [['label' => $setLabel, 'data' => array_values($data)]],
'datasets' => [['label' => $setLabel, 'data' => array_values($data)]],
];
}
}

View File

@@ -55,7 +55,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
$budgetIds = implode(',', $this->budgets->pluck('id')->toArray());
try {
$result = view('reports.budget.month', ['accountIds' => $accountIds, 'budgetIds' => $budgetIds])
$result = view('reports.budget.month', ['accountIds' => $accountIds, 'budgetIds' => $budgetIds])
->with('start', $this->start)
->with('end', $this->end)
->with('budgets', $this->budgets)

View File

@@ -58,7 +58,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
// render!
try {
return view('reports.category.month', ['accountIds' => $accountIds, 'categoryIds' => $categoryIds, 'reportType' => $reportType])
return view('reports.category.month', ['accountIds' => $accountIds, 'categoryIds' => $categoryIds, 'reportType' => $reportType])
->with('start', $this->start)
->with('end', $this->end)
->with('categories', $this->categories)

View File

@@ -63,7 +63,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
// render!
try {
$result = view('reports.tag.month', ['accountIds' => $accountIds, 'reportType' => $reportType, 'tagIds' => $tagIds])
$result = view('reports.tag.month', ['accountIds' => $accountIds, 'reportType' => $reportType, 'tagIds' => $tagIds])
->with('start', $this->start)
->with('end', $this->end)
->with('tags', $this->tags)

View File

@@ -54,11 +54,10 @@ class DeletedAccountObserver
->pluck('transaction_journal_id')
->toArray()
;
$groupIds = TransactionJournal::whereIn('id', $journalIds)
->get(['transaction_journals.transaction_group_id'])
->pluck('transaction_group_id')
->toArray()
;
$groupIds = array_map(function (array $item) {
return $item['transaction_group_id'];
}, TransactionJournal::whereIn('id', $journalIds)->get(['transaction_journals.transaction_group_id'])->toArray());
if (count($journalIds) > 0) {
Transaction::whereIn('transaction_journal_id', $journalIds)->delete();

View File

@@ -34,11 +34,8 @@ use FireflyIII\Support\Http\Controllers\ModelInformation;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* Class CreateController
@@ -87,7 +84,7 @@ final class CreateController extends Controller
'zoom_level' => $hasOldInput ? old('location_zoom_level') : config('firefly.default_location.zoom_level'),
'has_location' => $hasOldInput && 'true' === old('location_has_location'),
]];
$liabilityDirections = ['debit' => trans('firefly.liability_direction_debit'), 'credit' => trans('firefly.liability_direction_credit')];
$liabilityDirections = ['debit' => trans('firefly.liability_direction_debit'), 'credit' => trans('firefly.liability_direction_credit')];
// interest calculation periods:
$interestPeriods = [];
@@ -126,15 +123,7 @@ final class CreateController extends Controller
]);
}
/**
* Store the new account.
*
* @return Redirector|RedirectResponse
*
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function store(AccountFormRequest $request)
public function store(AccountFormRequest $request): RedirectResponse
{
$data = $request->getAccountData();
$account = $this->repository->store($data);

View File

@@ -63,7 +63,7 @@ final class DeleteController extends Controller
/**
* Delete account screen.
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*/
public function delete(Account $account): Factory|\Illuminate\Contracts\View\View|Redirector|RedirectResponse
{
@@ -80,13 +80,13 @@ final class DeleteController extends Controller
// put previous url in session
$this->rememberPreviousUrl('accounts.delete.url');
return view('accounts.delete', ['account' => $account, 'subTitle' => $subTitle, 'accountList' => $accountList, 'objectType' => $objectType]);
return view('accounts.delete', ['account' => $account, 'subTitle' => $subTitle, 'accountList' => $accountList, 'objectType' => $objectType]);
}
/**
* Delete the account.
*/
public function destroy(Request $request, Account $account): Redirector|RedirectResponse
public function destroy(Request $request, Account $account): RedirectResponse
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account);

View File

@@ -74,7 +74,7 @@ final class EditController extends Controller
*
* @SuppressWarnings("PHPMD.NPathComplexity")
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*/
public function edit(
Request $request,
@@ -103,7 +103,7 @@ final class EditController extends Controller
'has_location' => $hasLocation || 'true' === old('location_has_location'),
]];
$liabilityDirections = ['debit' => trans('firefly.liability_direction_debit'), 'credit' => trans('firefly.liability_direction_credit')];
$liabilityDirections = ['debit' => trans('firefly.liability_direction_debit'), 'credit' => trans('firefly.liability_direction_credit')];
// interest calculation periods:
$interestPeriods = [];
@@ -181,7 +181,7 @@ final class EditController extends Controller
/**
* Update the account.
*
* @return $this|Redirector|RedirectResponse
* @return RedirectResponse
*/
public function update(AccountFormRequest $request, Account $account)
{

View File

@@ -74,7 +74,7 @@ final class ReconcileController extends Controller
/**
* Reconciliation overview.
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*
* @throws FireflyException
* */
@@ -166,7 +166,7 @@ final class ReconcileController extends Controller
*
* @throws DuplicateTransactionException
*/
public function submit(ReconciliationStoreRequest $request, Account $account, Carbon $start, Carbon $end): Redirector|RedirectResponse
public function submit(ReconciliationStoreRequest $request, Account $account, Carbon $start, Carbon $end): RedirectResponse
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account);

View File

@@ -77,7 +77,7 @@ final class ShowController extends Controller
/**
* Show an account.
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*
* @throws ContainerExceptionInterface
* @throws FireflyException
@@ -121,7 +121,7 @@ final class ShowController extends Controller
$currency = $accountCurrency ?? $this->primaryCurrency;
$fStart = $start->isoFormat($this->monthAndDayFormat);
$fEnd = $end->isoFormat($this->monthAndDayFormat);
$subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
$subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$firstTransaction = $this->repository->oldestJournalDate($account) ?? $start;
@@ -197,7 +197,7 @@ final class ShowController extends Controller
/**
* Show an account.
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface

View File

@@ -65,6 +65,6 @@ final class HomeController extends Controller
$email = $pref->data;
}
return view('settings.index', ['title' => $title, 'mainTitleIcon' => $mainTitleIcon, 'email' => $email]);
return view('settings.index', ['title' => $title, 'mainTitleIcon' => $mainTitleIcon, 'email' => $email]);
}
}

View File

@@ -77,13 +77,13 @@ final class LinkController extends Controller
$this->rememberPreviousUrl('link-types.create.url');
}
return view('settings.link.create', ['subTitle' => $subTitle, 'subTitleIcon' => $subTitleIcon]);
return view('settings.link.create', ['subTitle' => $subTitle, 'subTitleIcon' => $subTitleIcon]);
}
/**
* Delete a link form.
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*/
public function delete(Request $request, LinkType $linkType): Factory|\Illuminate\Contracts\View\View|Redirector|RedirectResponse
{
@@ -110,13 +110,13 @@ final class LinkController extends Controller
// put previous url in session
$this->rememberPreviousUrl('link-types.delete.url');
return view('settings.link.delete', ['linkType' => $linkType, 'subTitle' => $subTitle, 'moveTo' => $moveTo, 'count' => $count]);
return view('settings.link.delete', ['linkType' => $linkType, 'subTitle' => $subTitle, 'moveTo' => $moveTo, 'count' => $count]);
}
/**
* Actually destroy the link.
*/
public function destroy(Request $request, LinkType $linkType): Redirector|RedirectResponse
public function destroy(Request $request, LinkType $linkType): RedirectResponse
{
Log::channel('audit')->info(sprintf('User destroyed link type #%d', $linkType->id));
$name = $linkType->name;
@@ -132,7 +132,7 @@ final class LinkController extends Controller
/**
* Edit a link form.
*
* @return Factory|Redirector|RedirectResponse|View
* @return Factory|RedirectResponse|View
*/
public function edit(Request $request, LinkType $linkType): Factory|\Illuminate\Contracts\View\View|Redirector|RedirectResponse
{
@@ -152,7 +152,7 @@ final class LinkController extends Controller
}
$request->session()->forget('link-types.edit.fromUpdate');
return view('settings.link.edit', ['subTitle' => $subTitle, 'subTitleIcon' => $subTitleIcon, 'linkType' => $linkType]);
return view('settings.link.edit', ['subTitle' => $subTitle, 'subTitleIcon' => $subTitleIcon, 'linkType' => $linkType]);
}
/**
@@ -171,7 +171,7 @@ final class LinkController extends Controller
$linkType->journalCount = $this->repository->countJournals($linkType);
});
return view('settings.link.index', ['subTitle' => $subTitle, 'subTitleIcon' => $subTitleIcon, 'linkTypes' => $linkTypes]);
return view('settings.link.index', ['subTitle' => $subTitle, 'subTitleIcon' => $subTitleIcon, 'linkTypes' => $linkTypes]);
}
/**
@@ -198,7 +198,7 @@ final class LinkController extends Controller
/**
* Store the new link.
*
* @return $this|Redirector|RedirectResponse
* @return RedirectResponse
*/
public function store(LinkTypeFormRequest $request)
{
@@ -227,7 +227,7 @@ final class LinkController extends Controller
/**
* Update an existing link.
*
* @return $this|Redirector|RedirectResponse
* @return RedirectResponse
*/
public function update(LinkTypeFormRequest $request, LinkType $linkType)
{
@@ -237,7 +237,7 @@ final class LinkController extends Controller
return redirect(route('settings.links.index'));
}
$data = ['name' => $request->convertString('name'), 'inward' => $request->convertString('inward'), 'outward' => $request->convertString('outward')];
$data = ['name' => $request->convertString('name'), 'inward' => $request->convertString('inward'), 'outward' => $request->convertString('outward')];
$this->repository->update($linkType, $data);
Log::channel('audit')->info(sprintf('User update link type #%d.', $linkType->id), $data);

View File

@@ -124,8 +124,16 @@ final class NotificationController extends Controller
return redirect(route('settings.notification.index'));
}
$all = $request->all();
$channel = $all['test_submit'] ?? '';
/** @var int $lastNotification */
$lastNotification = FireflyConfig::get('last_test_notification', 123)->data;
if ((time() - $lastNotification) < 120) {
session()->flash('error', (string) trans('firefly.test_rate_limited'));
return redirect(route('settings.notification.index'));
}
$all = $request->all();
$channel = $all['test_submit'] ?? '';
switch ($channel) {
default:
@@ -142,6 +150,7 @@ final class NotificationController extends Controller
event(new OwnerTestsNotificationChannel($channel, $owner));
session()->flash('success', (string) trans('firefly.notification_test_executed', ['channel' => $channel]));
}
FireflyConfig::set('last_test_notification', time());
return redirect(route('settings.notification.index'));
}

View File

@@ -31,7 +31,6 @@ use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
/**
@@ -94,7 +93,7 @@ final class UpdateController extends Controller
/**
* Post new settings.
*/
public function post(Request $request): Redirector|RedirectResponse
public function post(Request $request): RedirectResponse
{
$checkForUpdates = (int) $request->get('check_for_updates');
$channel = $request->get('update_channel');
@@ -123,7 +122,7 @@ final class UpdateController extends Controller
if ($release->isNewVersionAvailable()) {
// if running develop, slightly different message.
if (str_contains(config('firefly.version'), 'develop')) {
$message = trans('firefly.update_current_dev_older', ['version' => config('firefly.version'), 'new_version' => $release->getNewVersion()]);
$message = trans('firefly.update_current_dev_older', ['version' => config('firefly.version'), 'new_version' => $release->getNewVersion()]);
}
if (!str_contains(config('firefly.version'), 'develop')) {
$message = trans('firefly.update_new_version_alert', [

View File

@@ -34,7 +34,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
@@ -70,9 +69,6 @@ final class UserController extends Controller
$this->externalIdentity = 'web' !== config('firefly.authentication_guard');
}
/**
* @return Application|Factory|Redirector|RedirectResponse|View
*/
public function delete(User $user): Factory|\Illuminate\Contracts\View\View|Redirector|RedirectResponse
{
if ($this->externalIdentity) {
@@ -83,7 +79,7 @@ final class UserController extends Controller
$subTitle = (string) trans('firefly.delete_user', ['email' => $user->email]);
return view('settings.users.delete', ['user' => $user, 'subTitle' => $subTitle]);
return view('settings.users.delete', ['user' => $user, 'subTitle' => $subTitle]);
}
public function deleteInvite(InvitedUser $invitedUser): JsonResponse
@@ -105,7 +101,7 @@ final class UserController extends Controller
/**
* Destroy a user.
*/
public function destroy(User $user): Redirector|RedirectResponse
public function destroy(User $user): RedirectResponse
{
if ($this->externalIdentity) {
request()->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
@@ -233,7 +229,7 @@ final class UserController extends Controller
/**
* Update single user.
*
* @return $this|Redirector|RedirectResponse
* @return RedirectResponse
*/
public function update(UserFormRequest $request, User $user)
{

View File

@@ -32,7 +32,6 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response as LaravelResponse;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
/**
@@ -71,13 +70,13 @@ final class AttachmentController extends Controller
// put previous url in session
$this->rememberPreviousUrl('attachments.delete.url');
return view('attachments.delete', ['attachment' => $attachment, 'subTitle' => $subTitle]);
return view('attachments.delete', ['attachment' => $attachment, 'subTitle' => $subTitle]);
}
/**
* Destroy attachment.
*/
public function destroy(Request $request, Attachment $attachment): Redirector|RedirectResponse
public function destroy(Request $request, Attachment $attachment): RedirectResponse
{
$name = $attachment->filename;
@@ -141,7 +140,7 @@ final class AttachmentController extends Controller
$preFilled = ['notes' => $this->repository->getNoteText($attachment)];
$request->session()->flash('preFilled', $preFilled);
return view('attachments.edit', ['attachment' => $attachment, 'subTitleIcon' => $subTitleIcon, 'subTitle' => $subTitle]);
return view('attachments.edit', ['attachment' => $attachment, 'subTitleIcon' => $subTitleIcon, 'subTitle' => $subTitle]);
}
/**

View File

@@ -130,7 +130,7 @@ final class ForgotPasswordController extends Controller
$allowRegistration = false;
}
return view('auth.passwords.email')->with(['allowRegistration' => $allowRegistration, 'pageTitle' => $pageTitle]);
return view('auth.passwords.email')->with(['allowRegistration' => $allowRegistration, 'pageTitle' => $pageTitle]);
}
/**

View File

@@ -27,14 +27,12 @@ use Carbon\Carbon;
use FireflyIII\Events\Security\System\UnknownUserTriedLogin;
use FireflyIII\Events\Security\User\UserFailedLoginAttempt;
use FireflyIII\Events\Security\User\UserSuccessfullyLoggedIn;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Providers\RouteServiceProvider;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
@@ -48,8 +46,6 @@ use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\HttpFoundation\Response as ResponseAlias;
/**
@@ -153,7 +149,7 @@ final class LoginController extends Controller
/**
* Log the user out of the application.
*/
public function logout(Request $request): Redirector|RedirectResponse|Response
public function logout(Request $request): RedirectResponse|Response
{
$authGuard = config('firefly.authentication_guard');
$logoutUrl = config('firefly.custom_logout_url');
@@ -181,12 +177,6 @@ final class LoginController extends Controller
/**
* Show the application's login form.
*
* @return Application|Factory|Redirector|RedirectResponse|View
*
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function showLoginForm(Request $request): Factory|Redirector|RedirectResponse|View
{

View File

@@ -31,14 +31,11 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Http\Controllers\CreateStuff;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -75,15 +72,7 @@ final class RegisterController extends Controller
}
}
/**
* Handle a registration request for the application.
*
* @return Application|Redirector|RedirectResponse
*
* @throws FireflyException
* @throws ValidationException
*/
public function register(Request $request): Redirector|RedirectResponse
public function register(Request $request): RedirectResponse
{
$allowRegistration = $this->allowedToRegister();
$inviteCode = (string) $request->get('invite_code');
@@ -144,7 +133,7 @@ final class RegisterController extends Controller
$email = $request->old('email');
return view('auth.register', ['isDemoSite' => $isDemoSite, 'email' => $email, 'pageTitle' => $pageTitle, 'inviteCode' => $inviteCode]);
return view('auth.register', ['isDemoSite' => $isDemoSite, 'email' => $email, 'pageTitle' => $pageTitle, 'inviteCode' => $inviteCode]);
}
/**
@@ -170,7 +159,7 @@ final class RegisterController extends Controller
$email = $request?->old('email');
return view('auth.register', ['isDemoSite' => $isDemoSite, 'email' => $email, 'pageTitle' => $pageTitle]);
return view('auth.register', ['isDemoSite' => $isDemoSite, 'email' => $email, 'pageTitle' => $pageTitle]);
}
/**

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