Compare commits

...

72 Commits

Author SHA1 Message Date
github-actions[bot]
889ba9f3e6 Merge pull request #11990 from firefly-iii/release-1773991497
🤖 Automatically merge the PR into the develop branch.
2026-03-20 08:25:08 +01:00
JC5
32fe62df03 🤖 Auto commit for release 'develop' on 2026-03-20 2026-03-20 08:24:57 +01:00
James Cole
b3d048eb67 Fix https://github.com/orgs/firefly-iii/discussions/11977 2026-03-20 06:01:23 +01:00
James Cole
f7c01e6821 Restore v2 layout in dev. 2026-03-18 06:10:21 +01:00
James Cole
3a971d738c Fix https://github.com/firefly-iii/firefly-iii/issues/11976 2026-03-18 05:33:42 +01:00
James Cole
1eb4ae3a2c Fix a variety of Mago issues. 2026-03-18 05:26:50 +01:00
James Cole
0f30eb59a4 Fix https://github.com/firefly-iii/firefly-iii/issues/11978 2026-03-18 05:10:25 +01:00
James Cole
9c10b01e8b Small code fixes. 2026-03-17 20:43:32 +01:00
James Cole
7c4f80a360 Small changes based on Mago rule 2026-03-17 17:29:24 +01:00
James Cole
e5c19f6088 Fix https://github.com/firefly-iii/firefly-iii/issues/11969 2026-03-17 16:26:57 +01:00
James Cole
b067215ba8 Merge pull request #11974 from NorskNoobing/patch-1 2026-03-17 10:57:44 +01:00
Daniel Holøien
a17d10b064 Fix typo in SMTP server comment in .env.example
Signed-off-by: Daniel Holøien <39239702+NorskNoobing@users.noreply.github.com>
2026-03-17 07:52:36 +01:00
github-actions[bot]
859fea532d Merge pull request #11967 from firefly-iii/release-1773691728
🤖 Automatically merge the PR into the develop branch.
2026-03-16 21:10:01 +01:00
JC5
75261a46d9 🤖 Auto commit for release 'develop' on 2026-03-16 2026-03-16 21:08:48 +01:00
James Cole
a4a99310ea Fix bad comparison. 2026-03-16 21:02:52 +01:00
James Cole
8de0844e55 Remove old fields for tag 2026-03-16 20:54:57 +01:00
James Cole
e7a6dd792f Another fix for https://github.com/firefly-iii/firefly-iii/issues/11964 2026-03-16 20:43:05 +01:00
James Cole
395ccf8f75 Update changelog. 2026-03-16 20:27:57 +01:00
James Cole
dfbfdb6aa2 Fix https://github.com/firefly-iii/firefly-iii/issues/11964 2026-03-16 20:26:57 +01:00
James Cole
a367ee96bd Merge branch 'main' into develop 2026-03-16 20:18:25 +01:00
James Cole
b6b1261df5 Fix https://github.com/firefly-iii/firefly-iii/issues/11966 2026-03-16 20:17:52 +01:00
github-actions[bot]
52b611d7b3 Merge pull request #11962 from firefly-iii/release-1773633936
🤖 Automatically merge the PR into the develop branch.
2026-03-16 05:05:46 +01:00
JC5
bbc96f457b 🤖 Auto commit for release 'develop' on 2026-03-16 2026-03-16 05:05:36 +01:00
github-actions[bot]
490c421ae5 Merge pull request #11957 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-03-15 17:36:55 +01:00
github-actions[bot]
48e5adbbfd Merge pull request #11956 from firefly-iii/release-1773592601
🤖 Automatically merge the PR into the develop branch.
2026-03-15 17:36:50 +01:00
JC5
b123f7e6f1 🤖 Auto commit for release 'v6.5.6' on 2026-03-15 2026-03-15 17:36:42 +01:00
github-actions[bot]
bff351bad2 Merge pull request #11955 from firefly-iii/release-1773592137
🤖 Automatically merge the PR into the develop branch.
2026-03-15 17:29:07 +01:00
JC5
2f0a3238c3 🤖 Auto commit for release 'develop' on 2026-03-15 2026-03-15 17:28:57 +01:00
James Cole
dc88781607 Add missing translation. 2026-03-15 17:23:05 +01:00
James Cole
d6c2698eae Fix https://github.com/firefly-iii/firefly-iii/issues/11954 and https://github.com/firefly-iii/firefly-iii/issues/11953 2026-03-15 17:15:22 +01:00
github-actions[bot]
aee804940b Merge pull request #11952 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-03-15 08:05:57 +01:00
github-actions[bot]
b53a756e5a Merge pull request #11951 from firefly-iii/release-1773558345
🤖 Automatically merge the PR into the develop branch.
2026-03-15 08:05:52 +01:00
JC5
ff5d83eba5 🤖 Auto commit for release 'v6.5.5' on 2026-03-15 2026-03-15 08:05:46 +01:00
James Cole
4c10c4a26f Change title for changelog. 2026-03-15 08:00:28 +01:00
James Cole
f75817b44d Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2026-03-15 07:51:38 +01:00
github-actions[bot]
9ad5dfd45b Merge pull request #11950 from firefly-iii/release-1773557001
🤖 Automatically merge the PR into the develop branch.
2026-03-15 07:43:27 +01:00
JC5
9e3b8e6232 🤖 Auto commit for release 'develop' on 2026-03-15 2026-03-15 07:43:21 +01:00
James Cole
6c3b4a77b5 Small changes 2026-03-15 07:42:27 +01:00
James Cole
34b5d9fcf6 Update changelog. 2026-03-15 07:37:41 +01:00
James Cole
12bbc91dca Some minor code cleanup. 2026-03-15 06:48:11 +01:00
James Cole
a77ff6a51f Expand changelog with fixed issues. 2026-03-14 20:44:58 +01:00
James Cole
62eb054c7f Fix class/id value. 2026-03-14 20:31:16 +01:00
James Cole
13536a2f65 Clean up some phpstan issues. 2026-03-14 20:26:38 +01:00
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
237 changed files with 1665 additions and 1092 deletions

View File

@@ -173,7 +173,7 @@ MAIL_ENCRYPTION=null
MAIL_SENDMAIL_COMMAND=
#
# If you use self-signed certificates for your STMP server, you can use the following settings.
# If you use self-signed certificates for your SMTP server, you can use the following settings.
#
MAIL_ALLOW_SELF_SIGNED=false
MAIL_VERIFY_PEER=true

23
.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,16 @@ 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. These reports are often not applicable, not actually a vulnerability, or just plain wrong. This takes time away from responding to
*actual* security vulnerabilities or suspected security vulnerabilities. If you use automated means to search for security vulnerabilities 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

@@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2026
- Daniel Holøien
- Matthew Grove
- Cinnamon Pyro
- R1DEN

View File

@@ -96,7 +96,7 @@ final class AccountController extends Controller
$nameWithBalance = $account->name;
$currency = $this->repository->getAccountCurrency($account) ?? $this->primaryCurrency;
$useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
if (in_array($account->accountType->type, $this->balanceTypes, strict: true)) {
// this one is correct.
Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = $allBalances[$account->id] ?? [];

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

@@ -83,6 +83,9 @@ final class ListController extends Controller
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
if (0 === count($journalIds)) {
$collector->findNothing();
}
$collector
->setUser($admin)
// filter on journal IDs.

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,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\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;

View File

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

View File

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

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

@@ -84,6 +84,9 @@ final class ListController extends Controller
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
if (0 === count($journalIds)) {
$collector->findNothing();
}
$collector
->setUser($admin)
// filter on journal IDs.

View File

@@ -63,7 +63,7 @@ final class AccountController extends Controller
$query = trim((string) $request->get('query'));
$field = trim((string) $request->get('field'));
$type = $request->get('type') ?? 'all';
if ('' === $query || !in_array($field, $this->validFields, true)) {
if ('' === $query || !in_array($field, $this->validFields, strict: true)) {
return response(null, 422);
}
Log::debug(sprintf('Now in account search("%s", "%s")', $field, $query));

View File

@@ -66,7 +66,7 @@ final class TransactionController extends Controller
$internalRef = (string) $request->attributes->get('internal_reference');
$notes = (string) $request->attributes->get('notes');
$description = (string) $request->attributes->get('description');
Log::debug(sprintf('Include deleted? %s', var_export($includeDeleted, true)));
Log::debug(sprintf('Include deleted? %s', var_export(value: $includeDeleted, return: true)));
if ('' !== $externalId) {
$count += $this->repository->countByMeta('external_id', $externalId, $includeDeleted);
Log::debug(sprintf('Search for transactions with external_identifier "%s", count is now %d', $externalId, $count));

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);
});
@@ -322,7 +323,7 @@ final class BasicController extends Controller
$today = today(config('app.timezone'));
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
$budgets = $this->budgetRepository->getActiveBudgets();
$spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets);
$spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets, null, true);
$days = (int) $today->diffInDays($end, true) + 1;
$currencies = [];

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

@@ -38,7 +38,7 @@ class ApiRequest extends FormRequest
public function handleConfig(array $config): void
{
if (in_array('required', $config, true)) {
if (in_array('required', $config, strict: true)) {
$this->required = 'required';
}
}

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

@@ -28,7 +28,7 @@ use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Contracts\Validation\Validator;
use FireflyIII\Validation\FireflyValidator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
@@ -69,9 +69,9 @@ class ChartRequest extends FormRequest
];
}
public function withValidator(Validator $validator): void
public function withValidator(FireflyValidator $validator): void
{
$validator->after(static function (Validator $validator): void {
$validator->after(static function (FireflyValidator $validator): void {
// validate transaction query data.
$data = $validator->getData();
if (!array_key_exists('accounts', $data)) {

View File

@@ -27,7 +27,7 @@ namespace FireflyIII\Api\V1\Requests\Data\Bulk;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Contracts\Validation\Validator;
use FireflyIII\Validation\FireflyValidator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
@@ -61,9 +61,9 @@ class MoveTransactionsRequest extends FormRequest
* Configure the validator instance with special rules for after the basic validation rules.
* TODO this is duplicate.
*/
public function withValidator(Validator $validator): void
public function withValidator(FireflyValidator $validator): void
{
$validator->after(function (Validator $validator): void {
$validator->after(function (FireflyValidator $validator): void {
// validate start before end only if both are there.
$data = $validator->getData();
if (array_key_exists('original_account', $data) && array_key_exists('destination_account', $data)) {
@@ -75,7 +75,7 @@ class MoveTransactionsRequest extends FormRequest
}
}
private function validateMove(Validator $validator): void
private function validateMove(FireflyValidator $validator): void
{
$data = $validator->getData();
$repository = app(AccountRepositoryInterface::class);

View File

@@ -72,7 +72,7 @@ class GenericRequest extends FormRequest
if (in_array(
$type,
[AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value],
true
strict: true
)) {
$return->push($account);
}

View File

@@ -33,7 +33,7 @@ use FireflyIII\Rules\UniqueIban;
use FireflyIII\Support\Request\AppendsLocationData;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Contracts\Validation\Validator;
use FireflyIII\Validation\FireflyValidator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
@@ -121,9 +121,9 @@ class UpdateRequest extends FormRequest
/**
* Configure the validator instance with special rules for after the basic validation rules.
*/
public function withValidator(Validator $validator): void
public function withValidator(FireflyValidator $validator): void
{
$validator->after(function (Validator $validator): void {
$validator->after(function (FireflyValidator $validator): void {
// validate start before end only if both are there.
$data = $validator->getData();

View File

@@ -116,7 +116,7 @@ class StoreRequest extends FormRequest
$validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_currency'));
}
$type = $account->accountType->type;
if (!in_array($type, $types, true)) {
if (!in_array($type, $types, strict: true)) {
$validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_type'));
}
}

View File

@@ -51,7 +51,7 @@ class StoreRequest extends FormRequest
{
$fields = [
'title' => ['title', 'convertString'],
'description' => ['description', 'convertString'],
'description' => ['description', 'stringWithNewlines'],
'rule_group_id' => ['rule_group_id', 'convertInteger'],
'order' => ['order', 'convertInteger'],
'rule_group_title' => ['rule_group_title', 'convertString'],

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

@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\TransactionCurrency;
use FireflyIII\Api\V1\Requests\ApiRequest;
use Illuminate\Contracts\Validation\Validator;
use FireflyIII\Validation\FireflyValidator;
class CurrencyCodeRequest extends ApiRequest
{
@@ -34,10 +34,10 @@ class CurrencyCodeRequest extends ApiRequest
return ['code' => sprintf('exists:transaction_currencies,code|%s', $this->required)];
}
public function withValidator(Validator $validator): void
public function withValidator(FireflyValidator $validator): void
{
$validator->after(function (Validator $validator): void {
if (!$validator->valid()) {
$validator->after(function (FireflyValidator $validator): void {
if (0 === count($validator->valid())) {
return;
}
$code = $this->convertString('code', '');

View File

@@ -52,7 +52,7 @@ class CreateRequest extends FormRequest
$responses = $this->get('responses', []);
$deliveries = $this->get('deliveries', []);
if (in_array(0, [count($triggers), count($responses), count($deliveries)], true)) {
if (in_array(0, [count($triggers), count($responses), count($deliveries)], strict: true)) {
throw new FireflyException('Unexpectedly got no responses, triggers or deliveries.');
}

View File

@@ -53,7 +53,7 @@ class UpdateRequest extends FormRequest
$responses = $this->get('responses', []);
$deliveries = $this->get('deliveries', []);
if (in_array(0, [count($triggers), count($responses), count($deliveries)], true)) {
if (in_array(0, [count($triggers), count($responses), count($deliveries)], strict: true)) {
throw new FireflyException('Unexpectedly got no responses, triggers or deliveries.');
}

View File

@@ -56,10 +56,10 @@ class UpdateRequest extends FormRequest
public function getAll(): array
{
$name = $this->route()->parameter('dynamicConfigKey');
if (in_array($name, $this->booleans, true)) {
if (in_array($name, $this->booleans, strict: true)) {
return ['value' => $this->boolean('value')];
}
if (in_array($name, $this->integers, true)) {
if (in_array($name, $this->integers, strict: true)) {
return ['value' => $this->convertInteger('value')];
}
@@ -73,13 +73,13 @@ class UpdateRequest extends FormRequest
{
$name = $this->route()->parameter('configName');
if (in_array($name, $this->booleans, true)) {
if (in_array($name, $this->booleans, strict: true)) {
return ['value' => ['required', new IsBoolean()]];
}
if ('configuration.permission_update_check' === $name) {
return ['value' => 'required|numeric|min:-1|max:1'];
}
if (in_array($name, $this->integers, true)) {
if (in_array($name, $this->integers, strict: true)) {
return ['value' => 'required|numeric|min:464272080'];
}

View File

@@ -125,7 +125,7 @@ class CorrectsAccountTypes extends Command
private function canCreateDestination(array $validDestinations): bool
{
return in_array(AccountTypeEnum::EXPENSE->value, $validDestinations, true);
return in_array(AccountTypeEnum::EXPENSE->value, $validDestinations, strict: true);
}
/**
@@ -133,7 +133,7 @@ class CorrectsAccountTypes extends Command
*/
private function canCreateSource(array $validSources): bool
{
return in_array(AccountTypeEnum::REVENUE->value, $validSources, true);
return in_array(AccountTypeEnum::REVENUE->value, $validSources, strict: true);
}
private function fixJournal(TransactionJournal $journal, string $transactionType, Transaction $source, Transaction $dest): void
@@ -308,7 +308,7 @@ class CorrectsAccountTypes extends Command
private function hasValidAccountType(array $validTypes, string $accountType): bool
{
return in_array($accountType, $validTypes, true);
return in_array($accountType, $validTypes, strict: true);
}
private function inspectJournal(TransactionJournal $journal): void
@@ -342,7 +342,7 @@ class CorrectsAccountTypes extends Command
return;
}
$expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) {
if (!in_array($destAccountType, $expectedTypes, strict: true)) {
Log::debug(sprintf('[b] Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
}

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

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

@@ -86,10 +86,10 @@ class UpgradesToGroups extends Command
private function findOpposingTransaction(TransactionJournal $journal, Transaction $transaction): ?Transaction
{
$set = $journal->transactions->filter(static function (Transaction $subject) use ($transaction): bool {
$amount = ((float) $transaction->amount * -1) === (float) $subject->amount; // intentional float
$amount = -(float) $transaction->amount === (float) $subject->amount; // intentional float
$identifier = $transaction->identifier === $subject->identifier;
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
Log::debug(sprintf('ID the same? %s', var_export($identifier, true)));
Log::debug(sprintf('Amount the same? %s', var_export($amount, return: true)));
Log::debug(sprintf('ID the same? %s', var_export($identifier, return: true)));
return $amount && $identifier;
});

View File

@@ -250,6 +250,7 @@ class Handler extends ExceptionHandler
'json' => request()->acceptsJson(),
'method' => request()->method(),
'headers' => $headers,
// @mago-expect lint:no-request-all
'post' => 'POST' === request()->method() ? json_encode(request()->all()) : '',
];

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

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

@@ -56,11 +56,12 @@ class YearReportGenerator implements ReportGeneratorInterface
$reportType = 'default';
try {
$result = view('reports.default.year', ['accountIds' => $accountIds, 'reportType' => $reportType])
->with('start', $this->start)
->with('end', $this->end)
->render()
;
$result = view('reports.default.year', [
'accountIds' => $accountIds,
'reportType' => $reportType,
'start' => $this->start,
'end' => $this->end,
])->render();
} catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage()));
Log::error($e->getTraceAsString());

View File

@@ -63,13 +63,15 @@ class MonthReportGenerator implements ReportGeneratorInterface
// render!
try {
$result = view('reports.tag.month', ['accountIds' => $accountIds, 'reportType' => $reportType, 'tagIds' => $tagIds])
->with('start', $this->start)
->with('end', $this->end)
->with('tags', $this->tags)
->with('accounts', $this->accounts)
->render()
;
$result = view('reports.tag.month', [
'accountIds' => $accountIds,
'reportType' => $reportType,
'tagIds' => $tagIds,
'start' => $this->start,
'end' => $this->end,
'tags' => $this->tags,
'accounts' => $this->accounts,
])->render();
} catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.tag.month: %s', $e->getMessage()));
Log::error($e->getTraceAsString());

View File

@@ -955,9 +955,9 @@ trait MetaCollection
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
// $this->fields[] = 'tags.latitude as tag_latitude';
// $this->fields[] = 'tags.longitude as tag_longitude';
// $this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();

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->only(['channel']);
$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

@@ -33,7 +33,6 @@ 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;

View File

@@ -31,7 +31,6 @@ 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;
@@ -84,8 +83,8 @@ final class RegisterController extends Controller
throw new FireflyException('Registration is currently not available :(');
}
$this->validator($request->all())->validate();
$user = $this->createUser($request->all());
$this->validator($request->only(['email', 'password']))->validate();
$user = $this->createUser($request->only(['email', 'password']));
Log::info(sprintf('Registered new user %s', $user->email));
$owner = new OwnerNotifiable();
event(new NewUserRegistered($owner, $user));

View File

@@ -132,7 +132,7 @@ final class ResetPasswordController extends Controller
$allowRegistration = false;
}
return view('auth.passwords.reset')->with([
return view('auth.passwords.reset', [
'token' => $token,
'email' => $request->email,
'allowRegistration' => $allowRegistration,

View File

@@ -137,15 +137,15 @@ final class BudgetLimitController extends Controller
*/
public function store(Request $request): JsonResponse|RedirectResponse
{
Log::debug('Going to store new budget-limit.', $request->all());
Log::debug('Going to store new budget-limit.');
// first search for existing one and update it if necessary.
$currency = $this->currencyRepos->find((int) $request->get('transaction_currency_id'));
$budget = $this->repository->find((int) $request->get('budget_id'));
$currency = $this->currencyRepos->find((int) $request->input('transaction_currency_id'));
$budget = $this->repository->find((int) $request->input('budget_id'));
if (!$currency instanceof TransactionCurrency || !$budget instanceof Budget) {
throw new FireflyException('No valid currency or budget.');
}
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
$start = Carbon::createFromFormat('Y-m-d', $request->input('start'));
$end = Carbon::createFromFormat('Y-m-d', $request->input('end'));
if (!$start instanceof Carbon || !$end instanceof Carbon) {
return response()->json();
@@ -172,7 +172,7 @@ final class BudgetLimitController extends Controller
// return empty array:
return response()->json([]);
}
if ((int) $amount > 268435456) { // intentional cast to integer
if ((int) $amount > 268_435_456) { // intentional cast to integer
$amount = '268435456';
}
if (-1 === bccomp($amount, '0')) {
@@ -232,7 +232,7 @@ final class BudgetLimitController extends Controller
if ('' === $amount) {
$amount = '0';
}
if ((int) $amount > 268435456) { // 268 million, intentional integer
if ((int) $amount > 268_435_456) { // 268 million, intentional integer
$amount = '268435456';
}
// sanity check on amount:
@@ -254,8 +254,8 @@ final class BudgetLimitController extends Controller
$amount = bcmul($amount, '-1');
}
$notes = (string) $request->get('notes');
if (strlen($notes) > 32768) {
$notes = substr($notes, 0, 32768);
if (strlen($notes) > 32_768) {
$notes = substr($notes, 0, 32_768);
}
$limit = $this->blRepository->update($budgetLimit, ['amount' => $amount, 'notes' => $notes]);

View File

@@ -99,6 +99,7 @@ abstract class Controller extends BaseController
$logoutUrl = config('firefly.custom_logout_url');
// overrule v2 layout back to v1.
if ('true' === request()->get('force_default_layout') && 'v2' === config('view.layout')) {
// config('view.layout','v1');
Config::set('view.layout', 'v1');

View File

@@ -160,7 +160,7 @@ final class DebugController extends Controller
}
if ('' !== $logContent) {
// last few lines
$logContent = 'Truncated from this point <----|'.substr($logContent, -16384);
$logContent = 'Truncated from this point <----|'.substr($logContent, -16_384);
}
return view('debug', ['table' => $table, 'now' => $now, 'logContent' => $logContent]);
@@ -302,7 +302,7 @@ final class DebugController extends Controller
}
return [
'debug' => var_export(config('app.debug'), true),
'debug' => var_export(config('app.debug'), return: true),
'audit_log_channel' => implode(', ', config('logging.channels.audit.channels')),
'default_language' => (string) config('firefly.default_language'),
'default_locale' => (string) config('firefly.default_locale'),

View File

@@ -106,7 +106,7 @@ final class HomeController extends Controller
}
$request->session()->put('is_custom_range', $isCustomRange);
Log::debug(sprintf('Set is_custom_range to %s', var_export($isCustomRange, true)));
Log::debug(sprintf('Set is_custom_range to %s', var_export($isCustomRange, return: true)));
$request->session()->put('start', $start);
Log::debug(sprintf('Set start to %s', $start->format('Y-m-d H:i:s')));
$request->session()->put('end', $end);

View File

@@ -116,7 +116,7 @@ final class JavascriptController extends Controller
'currencyCode' => $currency->code,
'currencySymbol' => $currency->symbol,
'accountingLocaleInfo' => $accounting,
'anonymous' => var_export(Steam::anonymous(), true),
'anonymous' => var_export(Steam::anonymous(), return: true),
'language' => $lang,
'dateRangeTitle' => $dateRange['title'],
'locale' => $locale,

View File

@@ -60,6 +60,7 @@ final class BudgetController extends Controller
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->repository->cleanupBudgets();
$this->abRepository->cleanup();
return $next($request);
});

View File

@@ -82,7 +82,7 @@ final class IntroController extends Controller
Log::debug('Elements is array', $elements);
Log::debug('Keys is', array_keys($elements));
Log::debug(sprintf('Keys has "outro": %s', var_export($hasStep, true)));
Log::debug(sprintf('Keys has "outro": %s', var_export($hasStep, return: true)));
return $hasStep;
}

View File

@@ -135,7 +135,7 @@ final class AmountController extends Controller
*/
public function postAdd(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$data = $request->all();
$data = $request->only(['amount']);
$amounts = $data['amount'] ?? [];
$total = '0';
Log::debug('Start with loop.');

View File

@@ -231,8 +231,8 @@ final class PreferencesController extends Controller
Log::debug('postIndex for preferences.');
// front page accounts
$frontpageAccounts = [];
if (is_array($request->get('frontpageAccounts')) && count($request->get('frontpageAccounts')) > 0) {
foreach ($request->get('frontpageAccounts') as $id) {
if (is_array($request->input('frontpageAccounts')) && count($request->input('frontpageAccounts')) > 0) {
foreach ($request->input('frontpageAccounts') as $id) {
$frontpageAccounts[] = (int) $id;
}
Log::debug('Update frontpageAccounts', $frontpageAccounts);
@@ -240,7 +240,10 @@ final class PreferencesController extends Controller
}
// extract notifications:
$all = $request->all();
$keys = array_map(function (string $value): string {
return sprintf('notification_%s', $value);
}, array_keys(config('notifications.notifications.user')));
$all = $request->only($keys);
foreach (config('notifications.notifications.user') as $key => $info) {
$key = sprintf('notification_%s', $key);
if (array_key_exists($key, $all)) {
@@ -252,10 +255,11 @@ final class PreferencesController extends Controller
Preferences::set($key, false);
}
}
unset($all);
// view range:
Log::debug(sprintf('Let viewRange to "%s"', $request->get('viewRange')));
Preferences::set('viewRange', $request->get('viewRange'));
Log::debug(sprintf('Let viewRange to "%s"', $request->input('viewRange')));
Preferences::set('viewRange', $request->input('viewRange'));
// forget session values:
session()->forget('start');
session()->forget('end');
@@ -264,6 +268,7 @@ final class PreferencesController extends Controller
// notification settings, cannot be set by the demo user.
if (!auth()->user()->hasRole('demo')) {
$variables = ['slack_webhook_url', 'pushover_app_token', 'pushover_user_token', 'ntfy_server', 'ntfy_topic', 'ntfy_user', 'ntfy_pass'];
$all = $request->only($variables);
foreach ($variables as $variable) {
if ('' === $all[$variable]) {
Preferences::delete($variable);
@@ -274,9 +279,10 @@ final class PreferencesController extends Controller
}
Preferences::set('ntfy_auth', $all['ntfy_auth'] ?? false);
}
unset($all);
// convert primary
$convertToPrimary = 1 === (int) $request->get('convertToPrimary');
$convertToPrimary = 1 === (int) $request->input('convertToPrimary');
if ($convertToPrimary && !$this->convertToPrimary) {
// set to true!
Log::debug('User sets convertToPrimary to true.');
@@ -288,9 +294,9 @@ final class PreferencesController extends Controller
Preferences::set('convert_to_primary', $convertToPrimary);
// custom fiscal year
$customFiscalYear = 1 === (int) $request->get('customFiscalYear');
$customFiscalYear = 1 === (int) $request->input('customFiscalYear');
Preferences::set('customFiscalYear', $customFiscalYear);
$fiscalYearString = (string) $request->get('fiscalYearStart');
$fiscalYearString = (string) $request->input('fiscalYearStart');
if ('' !== $fiscalYearString) {
$fiscalYearStart = Carbon::parse($fiscalYearString, config('app.timezone'))->format('m-d');
Preferences::set('fiscalYearStart', $fiscalYearStart);
@@ -298,7 +304,7 @@ final class PreferencesController extends Controller
// save page size:
Preferences::set('listPageSize', 50);
$listPageSize = (int) $request->get('listPageSize');
$listPageSize = (int) $request->input('listPageSize');
if ($listPageSize > 0 && $listPageSize < 1337) {
Preferences::set('listPageSize', $listPageSize);
}
@@ -306,7 +312,7 @@ final class PreferencesController extends Controller
// language:
/** @var Preference $currentLang */
$currentLang = Preferences::get('language', 'en_US');
$lang = $request->get('language');
$lang = $request->input('language');
if (array_key_exists($lang, config('firefly.languages'))) {
Preferences::set('language', $lang);
}
@@ -317,13 +323,13 @@ final class PreferencesController extends Controller
// same for locale:
if (!auth()->user()->hasRole('demo')) {
$locale = (string) $request->get('locale');
$locale = (string) $request->input('locale');
$locale = '' === $locale ? null : $locale;
Preferences::set('locale', $locale);
}
// optional fields for transactions:
$setOptions = $request->get('tj') ?? [];
$setOptions = $request->input('tj') ?? [];
$optionalTj = [
'interest_date' => array_key_exists('interest_date', $setOptions),
'book_date' => array_key_exists('book_date', $setOptions),
@@ -341,13 +347,13 @@ final class PreferencesController extends Controller
Preferences::set('transaction_journal_optional_fields', $optionalTj);
// dark mode
$darkMode = $request->get('darkMode') ?? 'browser';
$darkMode = $request->input('darkMode') ?? 'browser';
if (in_array($darkMode, config('firefly.available_dark_modes'), true)) {
Preferences::set('darkMode', $darkMode);
}
// anonymous amounts?
$anonymous = '1' === $request->get('anonymous');
$anonymous = '1' === $request->input('anonymous');
Preferences::set('anonymous', $anonymous);
// save and continue
@@ -360,7 +366,7 @@ final class PreferencesController extends Controller
public function testNotification(Request $request): mixed
{
$all = $request->all();
$all = $request->only(['channel']);
$channel = $all['channel'] ?? '';
switch ($channel) {

View File

@@ -225,7 +225,7 @@ final class TagController extends Controller
{
// default values:
$subTitleIcon = 'fa-tag';
$page = (int) $request->get('page');
$page = (int) $request->input('page');
$pageSize = (int) Preferences::get('listPageSize', 50)->data;
$start ??= session('start');
$end ??= session('end');
@@ -249,18 +249,20 @@ final class TagController extends Controller
// collect transaction journal IDs in repository,
// this makes the collector faster and more accurate.
$journalIds = $this->repository->getJournalIds($tag);
if (0 === count($journalIds)) {
$collector->findNothing();
}
$collector
->setRange($start, $end)
->setLimit($pageSize)
->setPage($page)
->setJournalIds($journalIds)
->withAccountInformation()
// ->setTag($tag)
->withBudgetInformation()
->withCategoryInformation()
->withAttachmentInformation()
;
$groups = $collector->getPaginatedGroups();
$groups->setPath($path);
$sums = $this->repository->sumsOfTag($tag, $start, $end);
@@ -303,10 +305,13 @@ final class TagController extends Controller
// collect transaction journal IDs in repository,
// this makes the collector faster and more accurate.
$journalIds = $this->repository->getJournalIds($tag);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$journalIds = $this->repository->getJournalIds($tag);
if (0 === count($journalIds)) {
$collector->findNothing();
}
$collector
->setRange($start, $end)
->setLimit($pageSize)

View File

@@ -153,7 +153,7 @@ final class ConvertController extends Controller
foreach ($group->transactionJournals as $journal) {
// catch FF exception.
try {
$this->convertJournal($journal, $destinationType, $request->all());
$this->convertJournal($journal, $destinationType, $request->only(['source_id', 'source_name', 'destination_id', 'destination_name']));
} catch (FireflyException $e) {
session()->flash('error', $e->getMessage());

View File

@@ -115,7 +115,7 @@ final class EditController extends Controller
];
$optionalFields['external_url'] ??= false;
$optionalFields['location'] ??= false;
$optionalFields['location'] = $optionalFields['location']
$optionalFields['location'] = true === $optionalFields['location']
&& true === FireflyConfig::get('enable_external_map', config('firefly.enable_external_map'))->data;
// map info voor v2:

View File

@@ -43,6 +43,6 @@ final class EditController extends Controller
$mainTitleIcon = 'fa-book';
Log::debug(sprintf('Now at %s', __METHOD__));
return view('administrations.edit')->with(['title' => $title, 'subTitle' => $subTitle, 'mainTitleIcon' => $mainTitleIcon]);
return view('administrations.edit', ['title' => $title, 'subTitle' => $subTitle, 'mainTitleIcon' => $mainTitleIcon]);
}
}

View File

@@ -26,13 +26,11 @@ namespace FireflyIII\Http\Middleware;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\Handler;
use FireflyIII\User;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use League\OAuth2\Server\Exception\OAuthServerException;
/**
* Class Authenticate
@@ -100,7 +98,6 @@ class Authenticate
throw new FireflyException('This point is generally unreachable.');
//
// exit('five');
// foreach ($guards as $guard) {
// exit('six');

View File

@@ -205,7 +205,12 @@ class InterestingMessage
// send message about newly created transaction group.
/** @var null|TransactionGroup $group */
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int) $transactionGroupId);
$group = auth()
->user()
->transactionGroups()
->with(['transactionJournals', 'transactionJournals.transactionType'])
->find((int) $transactionGroupId)
;
if (null === $group) {
return;

View File

@@ -58,8 +58,10 @@ class SecureHeaders
"default-src 'none'",
"object-src 'none'",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s'", $nonce),
"style-src 'unsafe-inline' 'self'",
// sprintf("style-src 'self' 'nonce-%1s'", $nonce), // safe variant
"style-src 'self' 'unsafe-inline'", // unsafe variant
"base-uri 'self'",
// "form-action 'self'", // safe
"font-src 'self' data:",
sprintf("connect-src 'self' %s", $trackingScriptSrc),
sprintf("img-src 'self' data: 'nonce-%1s' ", $nonce),
@@ -68,14 +70,17 @@ class SecureHeaders
// overrule in development mode
if (true === config('firefly.is_local_dev')) {
$ip = '192.168.96.165';
$csp = [
"default-src 'none'",
"object-src 'none'",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s' https://firefly.sd.internal/_debugbar/assets", $nonce),
"style-src 'unsafe-inline' 'self' https://10.0.0.15:5173/",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s'", $nonce),
// sprintf("style-src 'self' 'nonce-%1s' https://10.0.0.15:5173/", $nonce), // safe variant
sprintf("style-src 'self' 'unsafe-inline' https://%s:5173/", $ip), // unsafe variant
"base-uri 'self'",
"font-src 'self' data: https://10.0.0.15:5173/",
sprintf("connect-src 'self' %s https://10.0.0.15:5173/ wss://10.0.0.15:5173/", $trackingScriptSrc),
"form-action 'self'",
sprintf("font-src 'self' data: https://%s:5173/", $ip),
sprintf('connect-src \'self\' %1$s https://%2$s:5173/ wss://%2$s:5173/', $trackingScriptSrc, $ip),
sprintf("img-src 'self' data: 'nonce-%1s'", $nonce),
"manifest-src 'self'",
];
@@ -89,7 +94,7 @@ class SecureHeaders
$customUrl = $logoutUrl;
}
if (null !== $route && 'oauth/authorize' !== $route->uri) {
if ('' !== $customUrl && null !== $route && 'oauth/authorize' !== $route->uri) {
$csp[] = sprintf("form-action 'self' %s", $customUrl);
}

View File

@@ -68,7 +68,7 @@ class ChecksForNewVersion implements ShouldQueue
$now = Carbon::now()->getTimestamp();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800) {
if ($diff < 604_800) {
Log::debug(sprintf('Checked for updates less than a week ago (on %s).', Carbon::createFromTimestamp($lastCheckTime->data)->format('Y-m-d H:i:s')));
return;
@@ -121,7 +121,7 @@ class ChecksForNewVersion implements ShouldQueue
$now = Carbon::now()->getTimestamp();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < (604800 * 4)) {
if ($diff < (604_800 * 4)) {
Log::debug(sprintf(
'Warned about updates less than four weeks ago (on %s).',
Carbon::createFromTimestamp($lastCheckTime->data)->format('Y-m-d H:i:s')

View File

@@ -31,6 +31,9 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property User $user
*/
class GroupMembership extends Model
{
use ReturnsIntegerIdTrait;

View File

@@ -73,7 +73,11 @@ class Preference extends Model
// try again with ID, but this time don't care about the preferred user_group_id
if (null === $preference) {
$preference = $user->preferences()->where('id', (int) $value)->first();
$preference = $user
->preferences()
->where('id', (int) $value)
->first()
;
}
if (null !== $preference) {
/** @var Preference $preference */

View File

@@ -32,6 +32,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use function Safe\json_decode;
use function Safe\json_encode;
/**
* @property TransactionJournal $transactionJournal
*/
class TransactionJournalMeta extends Model
{
use ReturnsIntegerIdTrait;

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
use Override;
/**

View File

@@ -27,6 +27,8 @@ use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
/**
@@ -37,6 +39,7 @@ use Illuminate\Support\Collection;
* @method getUser()
* @method checkUserGroupAccess(UserRoleEnum $role)
* @method setUserGroupById(int $userGroupId)
* @method setUser(null|Authenticatable|User $user)
*/
interface AttachmentRepositoryInterface
{

View File

@@ -638,9 +638,10 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
/** @var Bill $bill */
foreach ($bills as $bill) {
// Log::debug(sprintf('Bill #%d ("%s")', $bill->id, $bill->name));
/** @var Collection $set */
$set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
$currency = $convertToPrimary && $bill->transactionCurrency->id !== $primary->id ? $primary : $bill->transactionCurrency;
$set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
$currency = $convertToPrimary && $bill->transactionCurrency->id !== $primary->id ? $primary : $bill->transactionCurrency;
$return[(int) $currency->id] ??= [
'id' => (string) $currency->id,
'name' => $currency->name,
@@ -649,13 +650,14 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
'decimal_places' => $currency->decimal_places,
'sum' => '0',
];
$setAmount = '0';
// Log::debug(sprintf('Created a new array for currency #%d', $currency->id));
/** @var TransactionJournal $transactionJournal */
foreach ($set as $transactionJournal) {
// grab currency from transaction.
$transactionCurrency = $transactionJournal->transactionCurrency;
$return[(int) $transactionCurrency->id] ??= [
// grab currency from journal.
$transactionCurrency = $transactionJournal->transactionCurrency;
$currencyId = (int) $transactionCurrency->id;
$return[$currencyId] ??= [
'id' => (string) $transactionCurrency->id,
'name' => $transactionCurrency->name,
'symbol' => $transactionCurrency->symbol,
@@ -663,19 +665,12 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
'decimal_places' => $transactionCurrency->decimal_places,
'sum' => '0',
];
$amountFromJournal = Amount::getAmountFromJournalObject($transactionJournal);
// Log::debug(sprintf('Created a (new) array for currency #%d', $currencyId));
// Log::debug(sprintf('Amount to add is %s', $amountFromJournal));
// get currency from transaction as well.
$return[(int) $transactionCurrency->id]['sum'] = bcadd(
$return[(int) $transactionCurrency->id]['sum'],
Amount::getAmountFromJournalObject($transactionJournal)
);
// $setAmount = bcadd($setAmount, Amount::getAmountFromJournalObject($transactionJournal));
$return[$currencyId]['sum'] = bcadd($return[$currencyId]['sum'], $amountFromJournal);
}
// Log::debug(sprintf('Bill #%d ("%s") with %d transaction(s) and sum %s %s', $bill->id, $bill->name, $set->count(), $currency->code, $setAmount));
// $return[$currency->id]['sum'] = bcadd($return[$currency->id]['sum'], $setAmount);
// Log::debug(sprintf('Total sum is now %s', $return[$currency->id]['sum']));
}
// remove empty sets
$final = [];

View File

@@ -69,6 +69,21 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
}
$exists[$key] = true;
}
// grab budget limit currencies.
$currencies = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('budgets.user_id', $this->user->id)
->distinct()
->get(['budget_limits.transaction_currency_id'])
->pluck('transaction_currency_id')
->toArray()
;
// delete available budgets without these currencies.
$this->user
->availableBudgets()
->whereNotIn('transaction_currency_id', $currencies)
->delete()
;
}
/**

View File

@@ -256,8 +256,14 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
foreach ($budgets as $budget) {
DB::table('budget_transaction')->where('budget_id', $budget->id)->delete();
DB::table('budget_transaction_journal')->where('budget_id', $budget->id)->delete();
RecurrenceTransactionMeta::where('name', 'budget_id')->where('value', (string) $budget->id)->delete();
RuleAction::where('action_type', 'set_budget')->where('action_value', (string) $budget->id)->delete();
RecurrenceTransactionMeta::where('name', 'budget_id')
->where('value', (string) $budget->id)
->delete()
;
RuleAction::where('action_type', 'set_budget')
->where('action_value', (string) $budget->id)
->delete()
;
$budget->delete();
}
Log::channel('audit')->info('Delete all budgets through destroyAll');

View File

@@ -86,7 +86,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
$meta = AccountMeta::where('name', 'currency_id')
->where('data', json_encode((string) $currency->id))
->count()
;
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -94,7 +97,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
}
// second search using integer check.
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
$meta = AccountMeta::where('name', 'currency_id')
->where('data', json_encode((int) $currency->id))
->count()
;
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));

View File

@@ -116,8 +116,15 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
$links = $linkType->transactionJournalLinks()->get(['source_id', 'destination_id']);
$sources = $links->pluck('source_id')->toArray();
$destinations = $links->pluck('destination_id')->toArray();
$joined = array_unique(array_merge($sources, $destinations));
return array_unique(array_merge($sources, $destinations));
return $this->user
->transactionJournals()
->whereIn('id', $joined)
->get(['transaction_journals.id'])
->pluck('id')
->toArray()
;
}
/**

View File

@@ -25,7 +25,10 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PeriodStatistic;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\Category;
use FireflyIII\Models\PeriodStatistic;
use FireflyIII\Models\Tag;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder;
@@ -38,7 +41,7 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface, U
{
use UserGroupTrait;
public function allInRangeForModel(Model $model, Carbon $start, Carbon $end): Collection
public function allInRangeForModel(Account|Category|Tag $model, Carbon $start, Carbon $end): Collection
{
return $model->primaryPeriodStatistics()->where('start', '>=', $start)->where('end', '<=', $end)->get();
}

View File

@@ -25,13 +25,16 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PeriodStatistic;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\Category;
use FireflyIII\Models\PeriodStatistic;
use FireflyIII\Models\Tag;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
interface PeriodStatisticRepositoryInterface
{
public function allInRangeForModel(Model $model, Carbon $start, Carbon $end): Collection;
public function allInRangeForModel(Account|Category|Tag $model, Carbon $start, Carbon $end): Collection;
public function allInRangeForPrefix(string $prefix, Carbon $start, Carbon $end): Collection;
@@ -41,6 +44,8 @@ interface PeriodStatisticRepositoryInterface
public function deleteStatisticsForPrefix(string $prefix, Collection $dates): void;
public function deleteStatisticsForType(string $class, Collection $objects, Collection $dates): void;
public function findPeriodStatistic(Model $model, Carbon $start, Carbon $end, string $type): Collection;
public function findPeriodStatistics(Model $model, Carbon $start, Carbon $end, array $types): Collection;

View File

@@ -327,7 +327,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
$rule->userGroup()->associate($this->user->userGroup);
$rule->rule_group_id = $ruleGroup->id;
$rule->order = 31337;
$rule->order = 31_337;
$rule->active = array_key_exists('active', $data) ? $data['active'] : true;
$rule->strict = array_key_exists('strict', $data) ? $data['strict'] : false;
$rule->stop_processing = array_key_exists('stop_processing', $data) ? $data['stop_processing'] : false;

View File

@@ -382,7 +382,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
'user_group_id' => $this->user->user_group_id,
'title' => $data['title'],
'description' => $data['description'],
'order' => 31337,
'order' => 31_337,
'active' => array_key_exists('active', $data) ? $data['active'] : true,
]);
$newRuleGroup->save();

View File

@@ -96,6 +96,10 @@ class PrimaryAmountRecalculationService
Log::debug(sprintf('Recalculated %d transactions.', $set->count()));
}
/**
* Only recalculate accounts that have a virtual balance.
* TODO this routine must filter on accounts that are NOT in the userGroup's currency.
*/
private function recalculateAccounts(UserGroup $userGroup): void
{
$set = $userGroup
@@ -204,6 +208,9 @@ class PrimaryAmountRecalculationService
Log::debug(sprintf('Recalculated %d piggy bank events.', $set->count()));
}
/**
* This method collects ALL piggy banks, but only processes those that do not have the userGroup's primary currency.
*/
private function recalculatePiggyBanks(UserGroup $userGroup, TransactionCurrency $currency): void
{
$converter = new ExchangeRateConverter();

View File

@@ -695,6 +695,7 @@ class JournalUpdateService
$source = $this->getSourceTransaction();
$dest = $this->getDestinationTransaction();
$foreignCurrency = $source->foreignCurrency;
$oldForeignCurrency = $foreignCurrency;
$originalSourceAmount = $source->foreign_amount;
// find currency in data array
@@ -773,11 +774,15 @@ class JournalUpdateService
$this->transactionJournal,
'update_foreign_amount',
[
'currency_symbol' => $recordCurrency->symbol,
'decimal_places' => $recordCurrency->decimal_places,
'currency_symbol' => $oldForeignCurrency->symbol,
'decimal_places' => $oldForeignCurrency->decimal_places,
'amount' => $originalSourceAmount,
],
['currency_symbol' => $recordCurrency->symbol, 'decimal_places' => $recordCurrency->decimal_places, 'amount' => $value]
[
'currency_symbol' => $recordCurrency->symbol,
'decimal_places' => $recordCurrency->decimal_places,
'amount' => $value,
]
)
);
}

View File

@@ -225,21 +225,27 @@ class Amount
*/
public function getAmountFromJournalObject(TransactionJournal $journal): string
{
// Log::debug(sprintf('Get amount from journal #%d', $journal->id));
$convertToPrimary = $this->convertToPrimary();
$currency = $this->getPrimaryCurrency();
$field = $convertToPrimary && $currency->id !== $journal->transaction_currency_id ? 'pc_amount' : 'amount';
$field = $convertToPrimary && $currency->id !== $journal->transaction_currency_id ? 'native_amount' : 'amount';
/** @var null|Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
if (null === $sourceTransaction) {
// Log::debug('Return zero!');
return '0';
}
$amount = $sourceTransaction->{$field} ?? '0';
// Log::debug(sprintf('Amount is %s', $amount));
if ((int) $sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead!
$amount = (string) $sourceTransaction->foreign_amount; // hard coded to be foreign amount.
// Log::debug(sprintf('Amount is now %s', $amount));
}
// Log::debug(sprintf('Final return is %s', $amount));
return $amount;
}

View File

@@ -41,7 +41,10 @@ class UserGroupAccount implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$account = Account::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$account = Account::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $account) {
return $account;
}

View File

@@ -41,7 +41,10 @@ class UserGroupBill implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$currency = Bill::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$currency = Bill::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $currency) {
return $currency;
}

View File

@@ -38,7 +38,10 @@ class UserGroupExchangeRate implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$rate = CurrencyExchangeRate::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$rate = CurrencyExchangeRate::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $rate) {
return $rate;
}

View File

@@ -38,7 +38,10 @@ class UserGroupTransaction implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$group = TransactionGroup::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$group = TransactionGroup::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $group) {
return $group;
}

View File

@@ -171,7 +171,7 @@ class FrontpageChartGenerator
$direction = $array['sum_float'] < 0 ? 'spent' : 'earned';
$key = sprintf('%s-%d', $direction, $array['currency_id']);
$category = $array['name'];
$amount = $array['sum_float'] < 0 ? $array['sum_float'] * -1 : $array['sum_float'];
$amount = $array['sum_float'] < 0 ? -$array['sum_float'] : $array['sum_float'];
$currencyData[$key]['entries'][$category] = $amount;
}

View File

@@ -35,7 +35,7 @@ abstract class AbstractCronjob
public bool $jobFired = false;
public bool $jobSucceeded = false;
public ?string $message = null;
public int $timeBetweenRuns = 43200;
public int $timeBetweenRuns = 43_200;
protected Carbon $date;
protected bool $force = false;

View File

@@ -47,7 +47,7 @@ class AutoBudgetCronjob extends AbstractCronjob
Log::info('Auto budget cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been %s since the auto budget cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The auto budget cron-job will not fire now.');
@@ -58,7 +58,7 @@ class AutoBudgetCronjob extends AbstractCronjob
Log::info('Execution of the auto budget cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been %s since the auto budget cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -54,7 +54,7 @@ class BillWarningCronjob extends AbstractCronjob
Log::info('The bill notification cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been %s since the bill notification cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The cron-job will not fire now.');
@@ -69,7 +69,7 @@ class BillWarningCronjob extends AbstractCronjob
Log::info('Execution of the bill notification cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been %s since the bill notification cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -47,7 +47,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
Log::info('Exchange rates cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been %s since the exchange rates cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The exchange rates cron-job will not fire now.');
@@ -59,7 +59,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
Log::info('Execution of the exchange rates cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -54,7 +54,7 @@ class RecurringCronjob extends AbstractCronjob
Log::info('Recurring transactions cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The cron-job will not fire now.');
@@ -68,7 +68,7 @@ class RecurringCronjob extends AbstractCronjob
Log::info('Execution of the recurring transaction cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -60,7 +60,7 @@ class UpdateCheckCronjob extends AbstractCronjob
$now = Carbon::now()->getTimestamp();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800 && false === $this->force) {
if ($diff < 604_800 && false === $this->force) {
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = false;

View File

@@ -59,9 +59,9 @@ use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use League\Csv\AbstractCsv;
use League\Csv\CannotInsertRecord;
use League\Csv\Exception;
use League\Csv\Writer;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -284,7 +284,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -353,7 +353,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -412,7 +412,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -457,7 +457,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -537,7 +537,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -704,7 +704,7 @@ class ExportDataGenerator
}
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -851,7 +851,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -883,7 +883,7 @@ class ExportDataGenerator
*/
private function exportTags(): string
{
$header = ['user_id', 'tag_id', 'created_at', 'updated_at', 'tag', 'date', 'description', 'latitude', 'longitude', 'zoom_level'];
$header = ['user_id', 'tag_id', 'created_at', 'updated_at', 'tag', 'date', 'description']; // 'latitude', 'longitude', 'zoom_level'
$tagRepos = app(TagRepositoryInterface::class);
$tagRepos->setUser($this->user);
@@ -900,14 +900,14 @@ class ExportDataGenerator
$tag->tag,
$tag->date?->format('Y-m-d'),
$tag->description,
$tag->latitude,
$tag->longitude,
$tag->zoomLevel,
// $tag->latitude,
// $tag->longitude,
// $tag->zoomLevel,
];
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {
@@ -1103,7 +1103,7 @@ class ExportDataGenerator
}
// load the CSV document from a string
$csv = AbstractCsv::fromString();
$csv = Writer::fromString();
// insert the header
try {

View File

@@ -221,7 +221,7 @@ trait GetConfigurationData
return;
}
if (($now - $lastTime) > 129600) {
if (($now - $lastTime) > 129_600) {
request()->session()->flash('warning', trans('firefly.recurring_cron_long_ago'));
}
}

View File

@@ -111,6 +111,8 @@ trait UserNavigation
return redirect(route('index'));
}
/** @var TransactionJournal $journal */
$journal = $transaction->transactionJournal;
/** @var null|Transaction $other */

View File

@@ -111,6 +111,7 @@ class AvailableBudgetCalculator
$viewRange = Preferences::getForUser($this->user, 'viewRange', '1M')->data;
$viewRange = !is_string($viewRange) ? '1M' : $viewRange;
$this->viewRange = $this->correctViewRange($viewRange);
$this->abRepository->cleanup();
}
private function correctViewRange(string $viewRange): string

View File

@@ -27,8 +27,10 @@ namespace FireflyIII\Support\Request;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException;
use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
@@ -36,6 +38,8 @@ use function Safe\preg_replace;
/**
* Trait ConvertsDataTypes
*
* @method UserGroup validateUserGroup(Request $request)
*/
trait ConvertsDataTypes
{
@@ -231,7 +235,12 @@ trait ConvertsDataTypes
*/
public function stringWithNewlines(string $field): string
{
return (string) $this->clearStringKeepNewlines((string) ($this->get($field) ?? ''));
$entry = $this->get($field);
if (!is_scalar($entry)) {
return '';
}
return (string) $this->clearStringKeepNewlines((string) $entry);
}
/**

View File

@@ -48,7 +48,10 @@ class AppendNotes implements ActionInterface
public function actOnArray(array $journal): bool
{
$this->refreshNotes($journal);
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])->where('noteable_type', TransactionJournal::class)->first(['notes.*']);
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])
->where('noteable_type', TransactionJournal::class)
->first(['notes.*'])
;
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];

View File

@@ -44,7 +44,10 @@ class PrependNotes implements ActionInterface
public function actOnArray(array $journal): bool
{
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])->where('noteable_type', TransactionJournal::class)->first(['notes.*']);
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])
->where('noteable_type', TransactionJournal::class)
->first(['notes.*'])
;
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];

View File

@@ -255,7 +255,7 @@ class SearchRuleEngine implements RuleEngineInterface
$searchEngine = app(SearchInterface::class);
$searchEngine->setUser($this->user);
$searchEngine->setPage(1);
$searchEngine->setLimit(31337);
$searchEngine->setLimit(31_337);
foreach ($searchArray as $type => $value) {
$searchEngine->parseQuery(sprintf('%s:%s', $type, $value));
@@ -345,7 +345,7 @@ class SearchRuleEngine implements RuleEngineInterface
$searchEngine = app(SearchInterface::class);
$searchEngine->setUser($this->user);
$searchEngine->setPage(1);
$searchEngine->setLimit(31337);
$searchEngine->setLimit(31_337);
$searchEngine->setDate($date);
Log::debug('Search array', $searchArray);

View File

@@ -81,7 +81,7 @@ class AccountTransformer extends AbstractTransformer
}
// no order for some accounts:
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) {
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], strict: true)) {
$order = null;
}

View File

@@ -106,9 +106,6 @@ class User extends Authenticatable
throw new NotFoundHttpException();
}
/**
* Link to accounts.
*/
public function accounts(): HasMany
{
return $this->hasMany(Account::class);
@@ -527,7 +524,7 @@ class User extends Authenticatable
$userGroup->id,
$userGroup->title
));
if (in_array($membership->userRole->title, $dbRolesTitles, true)) {
if (in_array($membership->userRole->title, $dbRolesTitles, strict: true)) {
Log::debug(sprintf('Return true, found role "%s"', $membership->userRole->title));
return true;

View File

@@ -72,7 +72,7 @@ trait ValidatesAutoBudgetRequest
$validator->errors()->add('auto_budget_amount', (string) trans('validation.require_currency_info'));
}
// too big amount
if ((int) $amount > 268435456) {
if ((int) $amount > 268_435_456) {
$validator->errors()->add('auto_budget_amount', (string) trans('validation.amount_required_for_auto_budget'));
}
}

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