mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-03-20 12:20:20 +00:00
Compare commits
72 Commits
develop-20
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
889ba9f3e6 | ||
|
|
32fe62df03 | ||
|
|
b3d048eb67 | ||
|
|
f7c01e6821 | ||
|
|
3a971d738c | ||
|
|
1eb4ae3a2c | ||
|
|
0f30eb59a4 | ||
|
|
9c10b01e8b | ||
|
|
7c4f80a360 | ||
|
|
e5c19f6088 | ||
|
|
b067215ba8 | ||
|
|
a17d10b064 | ||
|
|
859fea532d | ||
|
|
75261a46d9 | ||
|
|
a4a99310ea | ||
|
|
8de0844e55 | ||
|
|
e7a6dd792f | ||
|
|
395ccf8f75 | ||
|
|
dfbfdb6aa2 | ||
|
|
a367ee96bd | ||
|
|
b6b1261df5 | ||
|
|
52b611d7b3 | ||
|
|
bbc96f457b | ||
|
|
490c421ae5 | ||
|
|
48e5adbbfd | ||
|
|
b123f7e6f1 | ||
|
|
bff351bad2 | ||
|
|
2f0a3238c3 | ||
|
|
dc88781607 | ||
|
|
d6c2698eae | ||
|
|
aee804940b | ||
|
|
b53a756e5a | ||
|
|
ff5d83eba5 | ||
|
|
4c10c4a26f | ||
|
|
f75817b44d | ||
|
|
9ad5dfd45b | ||
|
|
9e3b8e6232 | ||
|
|
6c3b4a77b5 | ||
|
|
34b5d9fcf6 | ||
|
|
12bbc91dca | ||
|
|
a77ff6a51f | ||
|
|
62eb054c7f | ||
|
|
13536a2f65 | ||
|
|
19dece287e | ||
|
|
897e1f773e | ||
|
|
5788e18d6d | ||
|
|
c8c4816fe8 | ||
|
|
aa57252b11 | ||
|
|
58e4c26a87 | ||
|
|
ac323f11c4 | ||
|
|
a907f9b2f7 | ||
|
|
8abd2a6604 | ||
|
|
0780390ff6 | ||
|
|
b9d1ed28a5 | ||
|
|
b8ebcdf1a8 | ||
|
|
ac8dbbff6c | ||
|
|
fea89c5231 | ||
|
|
654f2ee489 | ||
|
|
5c18624cf9 | ||
|
|
27ba8e842a | ||
|
|
e504ee204a | ||
|
|
a3a332643c | ||
|
|
464a89f305 | ||
|
|
062c2323e3 | ||
|
|
a37f995872 | ||
|
|
a5b6315cb8 | ||
|
|
ff568653c8 | ||
|
|
21447a9b2f | ||
|
|
238bfc819e | ||
|
|
3fab4668fc | ||
|
|
190050d6cf | ||
|
|
45d623e0c1 |
@@ -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
23
.github/security.md
vendored
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] ?? [];
|
||||
|
||||
@@ -185,6 +185,8 @@ final class DestroyController extends Controller
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budgetRepository->destroyAll();
|
||||
|
||||
$abRepository->cleanup();
|
||||
}
|
||||
|
||||
private function destroyCategories(): void
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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', '');
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
|
||||
|
||||
@@ -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.');
|
||||
|
||||
79
app/Console/Commands/SendTestEmail.php
Normal file
79
app/Console/Commands/SendTestEmail.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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()) : '',
|
||||
];
|
||||
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.');
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,8 @@ trait UserNavigation
|
||||
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $transaction->transactionJournal;
|
||||
|
||||
/** @var null|Transaction $other */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user