mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-03-07 00:11:45 +00:00
Compare commits
12 Commits
v6.5.4
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a08f776ffa | ||
|
|
e246c1f4b7 | ||
|
|
f2d1e8e184 | ||
|
|
19d8f46f24 | ||
|
|
9ac991edd7 | ||
|
|
e85f06792b | ||
|
|
b66f95f1dc | ||
|
|
4d63146524 | ||
|
|
695f990236 | ||
|
|
e882530a69 | ||
|
|
993a2491e9 | ||
|
|
f6ea517b5d |
12
.ci/php-cs-fixer/composer.lock
generated
12
.ci/php-cs-fixer/composer.lock
generated
@@ -1264,16 +1264,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "488285876e807a4777f074041d8bb508623419fa"
|
||||
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/488285876e807a4777f074041d8bb508623419fa",
|
||||
"reference": "488285876e807a4777f074041d8bb508623419fa",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
|
||||
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1330,7 +1330,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1350,7 +1350,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-25T16:59:43+00:00"
|
||||
"time": "2026-03-06T14:06:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
||||
@@ -14,10 +14,6 @@ parameters:
|
||||
enabled: false
|
||||
noNullableReturnTypeDeclaration:
|
||||
enabled: false
|
||||
privateInFinalClass:
|
||||
enabled: false
|
||||
noIsset:
|
||||
enabled: false
|
||||
finalInAbstractClass:
|
||||
enabled: false
|
||||
noConstructorParameterWithDefaultValue:
|
||||
@@ -38,50 +34,18 @@ parameters:
|
||||
reportUnmatchedIgnoredErrors: true
|
||||
ignoreErrors:
|
||||
# these are actually interesting but not right now:
|
||||
- identifier: staticMethod.dynamicCall
|
||||
- identifier: argument.templateType
|
||||
- identifier: method.childReturnType
|
||||
- identifier: instanceof.alwaysFalse
|
||||
- identifier: deadCode.unreachable
|
||||
- identifier: method.dynamicName
|
||||
- identifier: larastan.noEnvCallsOutsideOfConfig
|
||||
- identifier: property.notFound
|
||||
- identifier: arguments.count
|
||||
- identifier: staticMethod.dynamicName
|
||||
- identifier: catch.neverThrown
|
||||
- identifier: notIdentical.alwaysTrue
|
||||
- identifier: method.notFound
|
||||
- identifier: nullsafe.neverNull
|
||||
- identifier: identical.alwaysFalse
|
||||
- identifier: if.condNotBoolean
|
||||
# - identifier: booleanNot.exprNotBoolean
|
||||
- identifier: method.nonObject
|
||||
- identifier: function.impossibleType
|
||||
- identifier: booleanNot.exprNotBoolean
|
||||
- identifier: ternary.condNotBoolean
|
||||
- identifier: booleanNot.alwaysFalse
|
||||
- identifier: booleanAnd.alwaysFalse
|
||||
- identifier: greater.alwaysTrue
|
||||
- identifier: function.alreadyNarrowedType
|
||||
- identifier: booleanNot.alwaysTrue
|
||||
- identifier: property.phpDocType
|
||||
- identifier: nullCoalesce.offset
|
||||
- identifier: nullCoalesce.variable
|
||||
- identifier: larastan.noUnnecessaryCollectionCall
|
||||
- identifier: varTag.differentVariable
|
||||
- identifier: identical.alwaysTrue
|
||||
- identifier: clone.nonObject
|
||||
- identifier: assign.propertyReadOnly
|
||||
- identifier: property.nonObject
|
||||
- identifier: varTag.nativeType
|
||||
- identifier: booleanAnd.leftAlwaysFalse
|
||||
- identifier: property.onlyWritten
|
||||
- identifier: parameter.phpDocType
|
||||
- identifier: property.dynamicName
|
||||
- identifier: property.unusedType
|
||||
- identifier: staticMethod.deprecated
|
||||
- identifier: greater.invalid
|
||||
- identifier: instanceof.alwaysTrue
|
||||
# ignore everything but things that BREAK
|
||||
- identifier: property.deprecated
|
||||
- identifier: method.deprecated
|
||||
@@ -93,7 +57,15 @@ parameters:
|
||||
- identifier: assign.propertyType
|
||||
- identifier: return.unusedType
|
||||
- identifier: return.phpDocType
|
||||
# all errors below I will never fix.
|
||||
# all errors below I will (probably) never fix.
|
||||
- identifier: method.notFound # way too many false positives
|
||||
- identifier: catch.neverThrown # plenty of errors that are thrown undocumented
|
||||
- identifier: staticMethod.dynamicName # dont care
|
||||
- identifier: arguments.count # one false positive
|
||||
- identifier: property.notFound # false positives
|
||||
- identifier: method.dynamicName # i dont care
|
||||
- identifier: staticMethod.dynamicCall # many false positives.
|
||||
- identifier: argument.templateType # no clue how to fix single occurrence.
|
||||
# - '#expects view-string\|null, string given#'
|
||||
# - '#expects view-string, string given#'
|
||||
# - "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
|
||||
|
||||
@@ -63,6 +63,8 @@ abstract class Controller extends BaseController
|
||||
use ValidatesRequests;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
protected array $acceptedRoles = [];
|
||||
|
||||
protected const string CONTENT_TYPE = 'application/vnd.api+json';
|
||||
protected const string JSON_CONTENT_TYPE = 'application/json';
|
||||
|
||||
|
||||
@@ -112,19 +112,6 @@ final class BasicController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if date is outside session range.
|
||||
*/
|
||||
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool
|
||||
{ // Validate a preference
|
||||
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// start and end in the past? use $end
|
||||
return $start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date);
|
||||
}
|
||||
|
||||
private function getBalanceInformation(Carbon $start, Carbon $end): array
|
||||
{
|
||||
Log::debug('getBalanceInformation');
|
||||
|
||||
@@ -62,7 +62,7 @@ final class BatchController extends Controller
|
||||
}
|
||||
Log::debug(sprintf('Counted %d journals.', count($journals)));
|
||||
|
||||
/** @var TransactionJournal $first */
|
||||
/** @var null|TransactionJournal $first */
|
||||
$first = $journals->first();
|
||||
$group = $first?->transactionGroup;
|
||||
if (null === $group) {
|
||||
|
||||
@@ -34,7 +34,9 @@ abstract class AggregateFormRequest extends ApiRequest
|
||||
/**
|
||||
* @var ApiRequest[]
|
||||
*/
|
||||
protected array $requests = [];
|
||||
protected array $requests = [];
|
||||
|
||||
protected array $acceptedRoles = [];
|
||||
|
||||
#[Override]
|
||||
public function initialize(
|
||||
|
||||
@@ -38,7 +38,7 @@ class DateRangeRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$start = $this->getCarbonDate('start')?->startOfDay();
|
||||
|
||||
@@ -36,7 +36,7 @@ class DateRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$date = $this->getCarbonDate('date')?->endOfDay();
|
||||
|
||||
@@ -50,7 +50,7 @@ class ObjectTypeApiRequest extends ApiRequest
|
||||
|
||||
$this->objectType = $config['object_type'] ?? null;
|
||||
|
||||
if (!$this->objectType) {
|
||||
if (null === $this->objectType) {
|
||||
throw new RuntimeException('ObjectTypeApiRequest requires a object_type config');
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class ObjectTypeApiRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$type = $this->convertString('types', 'all');
|
||||
|
||||
@@ -42,7 +42,7 @@ class QueryRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$query = $this->convertString('query');
|
||||
|
||||
@@ -40,7 +40,7 @@ class AccountTypeApiRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class AccountTypesApiRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$types = explode(',', $this->convertString('types', 'all'));
|
||||
|
||||
@@ -40,6 +40,8 @@ class Request extends FormRequest
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
|
||||
protected array $acceptedRoles = [];
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||
@@ -85,6 +86,7 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
/** @var Budget $budget */
|
||||
$budget = $this->route()->parameter('budget');
|
||||
$validator->after(static function (Validator $validator) use ($budget): void {
|
||||
if (0 !== count($validator->failed())) {
|
||||
|
||||
@@ -61,7 +61,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var TransactionCurrency $currency */
|
||||
/** @var string|TransactionCurrency $currency */
|
||||
$currency = $this->route()->parameter('currency_code');
|
||||
if (is_string($currency)) {
|
||||
$currency = TransactionCurrency::whereCode($currency)->first();
|
||||
|
||||
@@ -41,7 +41,7 @@ class PaginationRequest extends ApiRequest
|
||||
|
||||
$this->sortClass = $config['sort_class'] ?? null;
|
||||
|
||||
if (!$this->sortClass) {
|
||||
if (null === $this->sortClass) {
|
||||
throw new RuntimeException('PaginationRequest requires a sort_class config');
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class PaginationRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class PaginationRequest extends ApiRequest
|
||||
$page = $this->convertInteger('page');
|
||||
$page = min(max(1, $page), 2 ** 16);
|
||||
$offset = ($page - 1) * $limit;
|
||||
$sort = $this->sortClass ? $this->convertSortParameters('sort', $this->sortClass) : $this->get('sort');
|
||||
$sort = null !== $this->sortClass ? $this->convertSortParameters('sort', $this->sortClass) : $this->get('sort');
|
||||
$this->attributes->set('limit', $limit);
|
||||
$this->attributes->set('sort', $sort);
|
||||
$this->attributes->set('page', $page);
|
||||
|
||||
@@ -45,7 +45,7 @@ class CountRequest extends AggregateFormRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$this->attributes->set('include_deleted', $this->convertBoolean($this->input('include_deleted', 'false')));
|
||||
|
||||
@@ -37,7 +37,7 @@ class SearchQueryRequest extends ApiRequest
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(function (Validator $validator): void {
|
||||
if ($validator->failed()) {
|
||||
if (count($validator->failed()) > 0) {
|
||||
return;
|
||||
}
|
||||
$query = $this->convertString('query');
|
||||
|
||||
@@ -57,24 +57,28 @@ class CorrectsIbans extends Command
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$userId = $account->user_id;
|
||||
$userId = $account->user_id;
|
||||
$set[$userId] ??= [];
|
||||
$iban = (string) $account->iban;
|
||||
$iban = (string) $account->iban;
|
||||
if ('' === $iban) {
|
||||
continue;
|
||||
}
|
||||
$type = $account->accountType->type;
|
||||
$type = $account->accountType->type;
|
||||
if (in_array($type, [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], true)) {
|
||||
$type = 'liabilities';
|
||||
}
|
||||
// iban already in use! two exceptions exist:
|
||||
if (
|
||||
array_key_exists($iban, $set[$userId]) && (
|
||||
!AccountTypeEnum::EXPENSE->value === $set[$userId][$iban]
|
||||
&& AccountTypeEnum::REVENUE->value === $type
|
||||
&& !(AccountTypeEnum::REVENUE->value === $set[$userId][$iban] && AccountTypeEnum::EXPENSE->value === $type)
|
||||
)
|
||||
) {
|
||||
$showWarningAndCorrect = false;
|
||||
if (array_key_exists($iban, $set[$userId])) {
|
||||
// the type is a revenue account, and the existing IBAN is NOT an expense account.
|
||||
if (AccountTypeEnum::REVENUE->value === $type && AccountTypeEnum::EXPENSE->value !== $set[$userId][$iban]) {
|
||||
$showWarningAndCorrect = true;
|
||||
}
|
||||
// the type is an expense account, and the existing IBAN is NOT a revenue account
|
||||
if (AccountTypeEnum::EXPENSE->value === $type && AccountTypeEnum::REVENUE->value !== $set[$userId][$iban]) {
|
||||
$showWarningAndCorrect = true;
|
||||
}
|
||||
}
|
||||
if ($showWarningAndCorrect) {
|
||||
$this->friendlyWarning(sprintf(
|
||||
'IBAN "%s" is used more than once and will be removed from %s #%d ("%s")',
|
||||
$iban,
|
||||
|
||||
@@ -69,10 +69,6 @@ class CorrectsInvertedBudgetLimits extends Command
|
||||
$budgetLimit->saveQuietly();
|
||||
}
|
||||
|
||||
if ($set->count() > 0) {
|
||||
// FIXME here be a available budget event.
|
||||
}
|
||||
|
||||
if (1 === $set->count()) {
|
||||
$this->friendlyInfo('Corrected one budget limit to have the right start/end dates.');
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ class CorrectsUnevenAmount extends Command
|
||||
foreach ($journals as $entry) {
|
||||
$sum = (string) $entry->the_sum;
|
||||
$sum = Steam::floatalize($sum);
|
||||
if (!is_numeric($sum) || '' === $sum || str_contains($sum, 'e') || str_contains($sum, ',')) {
|
||||
if (!is_numeric($sum) || str_contains($sum, 'e') || str_contains($sum, ',')) {
|
||||
$message = sprintf('Journal #%d has an invalid sum ("%s"). No sure what to do.', $entry->transaction_journal_id, $entry->the_sum);
|
||||
$this->friendlyWarning($message);
|
||||
Log::warning($message);
|
||||
|
||||
@@ -127,7 +127,7 @@ class RemovesDatabaseDecryption extends Command
|
||||
}
|
||||
|
||||
// A separate routine for preferences table:
|
||||
if ('preferences' === $table && is_string($value)) {
|
||||
if ('preferences' === $table) {
|
||||
$this->decryptPreferencesRow($id, $value);
|
||||
|
||||
return;
|
||||
|
||||
@@ -101,8 +101,13 @@ class UpgradesLiabilitiesEight extends Command
|
||||
|
||||
private function hasBadOpening(Account $account): bool
|
||||
{
|
||||
/** @var TransactionType $openingBalanceType */
|
||||
$openingBalanceType = TransactionType::whereType(TransactionTypeEnum::OPENING_BALANCE->value)->first();
|
||||
|
||||
/** @var TransactionType $liabilityType */
|
||||
$liabilityType = TransactionType::whereType(TransactionTypeEnum::LIABILITY_CREDIT->value)->first();
|
||||
|
||||
/** @var null|TransactionJournal $openingJournal */
|
||||
$openingJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->where('transaction_journals.transaction_type_id', $openingBalanceType->id)
|
||||
@@ -111,6 +116,8 @@ class UpgradesLiabilitiesEight extends Command
|
||||
if (null === $openingJournal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var null|TransactionJournal $liabilityJournal */
|
||||
$liabilityJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->where('transaction_journals.transaction_type_id', $liabilityType->id)
|
||||
@@ -120,7 +127,7 @@ class UpgradesLiabilitiesEight extends Command
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $openingJournal->date->isSameDay($liabilityJournal->date);
|
||||
return $openingJournal->date->isSameDay($liabilityJournal->date);
|
||||
}
|
||||
|
||||
private function isExecuted(): bool
|
||||
|
||||
@@ -36,7 +36,7 @@ final class IntervalException extends Exception
|
||||
public array $availableIntervals = [];
|
||||
public Periodicity $periodicity = Periodicity::Monthly;
|
||||
|
||||
/** @var mixed */
|
||||
/** @var string */
|
||||
protected $message = 'The periodicity %s is unknown. Choose one of available periodicity: %s';
|
||||
|
||||
public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null)
|
||||
|
||||
@@ -338,7 +338,7 @@ class TransactionJournalFactory
|
||||
'date_tz' => $carbon->format('e'),
|
||||
'order' => $order,
|
||||
'tag_count' => 0,
|
||||
'completed' => !$row['batch_submission'],
|
||||
'completed' => is_bool($row['batch_submission']) && !$row['batch_submission'],
|
||||
]);
|
||||
Log::debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description));
|
||||
|
||||
@@ -574,16 +574,11 @@ class TransactionJournalFactory
|
||||
return [$sourceAccount, $account];
|
||||
}
|
||||
|
||||
if (!$sourceAccount instanceof Account) {
|
||||
Log::debug('Source account is NULL, destination account is not.');
|
||||
$account = $this->accountRepository->getReconciliation($destinationAccount);
|
||||
Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type));
|
||||
Log::debug('Source account is NULL, destination account is not.');
|
||||
$account = $this->accountRepository->getReconciliation($destinationAccount);
|
||||
Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type));
|
||||
|
||||
return [$account, $destinationAccount];
|
||||
}
|
||||
Log::debug('Unused fallback');
|
||||
|
||||
return [$sourceAccount, $destinationAccount];
|
||||
return [$account, $destinationAccount];
|
||||
}
|
||||
|
||||
private function storeLocation(TransactionJournal $journal, NullArrayObject $data): void
|
||||
|
||||
@@ -275,7 +275,7 @@ final class LoginController extends Controller
|
||||
$request->session()->regenerate();
|
||||
$this->clearLoginAttempts($request);
|
||||
$response = $this->authenticated($request, $this->guard()->user());
|
||||
if ($response) {
|
||||
if (null !== $response) {
|
||||
return $response;
|
||||
}
|
||||
$path = Steam::getSafeUrl(session()->pull('url.intended', route('index')), route('index'));
|
||||
|
||||
@@ -176,7 +176,7 @@ final class RegisterController extends Controller
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function allowedToRegister(): bool
|
||||
private function allowedToRegister(): bool
|
||||
{
|
||||
// is allowed to register?
|
||||
$allowRegistration = true;
|
||||
|
||||
@@ -304,7 +304,7 @@ final class DebugController extends Controller
|
||||
|
||||
return [
|
||||
'debug' => var_export(config('app.debug'), true),
|
||||
'audit_log_channel' => envNonEmpty('AUDIT_LOG_CHANNEL', '(empty)'),
|
||||
'audit_log_channel' => implode(', ', config('logging.channels.audit.channels')),
|
||||
'default_language' => (string) config('firefly.default_language'),
|
||||
'default_locale' => (string) config('firefly.default_locale'),
|
||||
'remote_header' => 'remote_user_guard' === $userGuard ? config('auth.guard_header') : 'N/A',
|
||||
@@ -323,11 +323,11 @@ final class DebugController extends Controller
|
||||
private function getBuildInfo(): array
|
||||
{
|
||||
$return = [
|
||||
'is_docker' => env('IS_DOCKER', false),
|
||||
'is_docker' => config('firefly.is_docker'),
|
||||
'build' => '(unknown)',
|
||||
'build_date' => '(unknown)',
|
||||
'base_build' => '(unknown)',
|
||||
'base_build_date' => '(unknown)',
|
||||
'base_build' => config('firefly.base_image_build'),
|
||||
'base_build_date' => config('firefly.base_image_date'),
|
||||
];
|
||||
|
||||
try {
|
||||
@@ -348,12 +348,6 @@ final class DebugController extends Controller
|
||||
Log::debug('Could not check build date, but thats ok.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
if ('' !== (string) env('BASE_IMAGE_BUILD')) {
|
||||
$return['base_build'] = env('BASE_IMAGE_BUILD');
|
||||
}
|
||||
if ('' !== (string) env('BASE_IMAGE_DATE')) {
|
||||
$return['base_build_date'] = env('BASE_IMAGE_DATE');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ final class PreferencesController extends Controller
|
||||
AccountTypeEnum::DEBT->value,
|
||||
AccountTypeEnum::MORTGAGE->value,
|
||||
]);
|
||||
$isDocker = env('IS_DOCKER', false);
|
||||
$isDocker = config('firefly.is_docker');
|
||||
$groupedAccounts = [];
|
||||
|
||||
/** @var Account $account */
|
||||
|
||||
@@ -67,7 +67,7 @@ class SecureHeaders
|
||||
];
|
||||
|
||||
// overrule in development mode
|
||||
if (true === env('IS_LOCAL_DEV')) {
|
||||
if (true === config('firefly.is_local_dev')) {
|
||||
$csp = [
|
||||
"default-src 'none'",
|
||||
"object-src 'none'",
|
||||
|
||||
@@ -213,7 +213,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
/** @var RecurrenceTransaction $transaction */
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
$single = [
|
||||
'type' => null === $transaction?->transactionType?->type
|
||||
'type' => null === $transaction->transactionType?->type
|
||||
? strtolower((string) $recurrence->transactionType->type)
|
||||
: strtolower($transaction->transactionType->type),
|
||||
'date' => $date,
|
||||
|
||||
@@ -42,7 +42,7 @@ class ProcessesBudgetLimits implements ShouldQueue
|
||||
public function handle(CreatedBudgetLimit|DestroyedBudgetLimit|UpdatedBudgetLimit $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in ProcessesBudgetLimits::handle for event %s', get_class($event)));
|
||||
if ($event instanceof DestroyedBudgetLimit && null !== $event->user) {
|
||||
if ($event instanceof DestroyedBudgetLimit) {
|
||||
// need to recalculate all available budgets for this user.
|
||||
$calculator = new AvailableBudgetCalculator();
|
||||
$calculator->setUser($event->user);
|
||||
|
||||
@@ -58,10 +58,10 @@ class SendsWebhookMessages implements ShouldQueue
|
||||
$message->save();
|
||||
Log::debug(sprintf('Send message #%d', $message->id));
|
||||
SendWebhookMessage::dispatch($message)->afterResponse();
|
||||
|
||||
continue;
|
||||
}
|
||||
if (false !== $message->sent) {
|
||||
Log::debug(sprintf('Skip message #%d', $message->id));
|
||||
}
|
||||
Log::debug(sprintf('Skip message #%d', $message->id));
|
||||
}
|
||||
|
||||
// clean up sent messages table:
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Handlers\Observer\BillObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
@@ -38,6 +39,11 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* @property Carbon $date
|
||||
* @property null|Carbon $end_date
|
||||
* @property null|Carbon $extension_date
|
||||
*/
|
||||
#[ObservedBy([BillObserver::class])]
|
||||
class Bill extends Model
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
@@ -32,6 +33,9 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property Carbon $date
|
||||
*/
|
||||
class CurrencyExchangeRate extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
@@ -11,6 +12,10 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* @property Carbon $start
|
||||
* @property Carbon $end
|
||||
*/
|
||||
class PeriodStatistic extends Model
|
||||
{
|
||||
use ReturnsIntegerUserIdTrait;
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Handlers\Observer\PiggyBankObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
@@ -36,6 +37,10 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* @property null|Carbon $target_date
|
||||
* @property null|Carbon $start_date
|
||||
*/
|
||||
#[ObservedBy([PiggyBankObserver::class])]
|
||||
class PiggyBank extends Model
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Handlers\Observer\PiggyBankEventObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
@@ -31,6 +32,9 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property Carbon $date
|
||||
*/
|
||||
#[ObservedBy([PiggyBankEventObserver::class])]
|
||||
class PiggyBankEvent extends Model
|
||||
{
|
||||
|
||||
@@ -30,6 +30,9 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* @property mixed $data
|
||||
*/
|
||||
class Preference extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -40,8 +40,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* @property Carbon $first_date
|
||||
* @property null|Carbon $first_date
|
||||
* @property null|Carbon $latest_date
|
||||
* @property null|Carbon $repeat_until
|
||||
*/
|
||||
#[ObservedBy([DeletedRecurrenceObserver::class])]
|
||||
class Recurrence extends Model
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Handlers\Observer\DeletedTagObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
@@ -36,6 +37,9 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* @property null|Carbon $date
|
||||
*/
|
||||
#[ObservedBy([DeletedTagObserver::class])]
|
||||
class Tag extends Model
|
||||
{
|
||||
|
||||
@@ -47,7 +47,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method EloquentBuilder|static after()
|
||||
* @method static EloquentBuilder|static query()
|
||||
*
|
||||
* @property TransactionGroup $transactionGroup
|
||||
* @property null|TransactionGroup $transactionGroup
|
||||
* @property Carbon $date
|
||||
*/
|
||||
#[ObservedBy([DeletedTransactionJournalObserver::class])]
|
||||
class TransactionJournal extends Model
|
||||
|
||||
@@ -687,6 +687,31 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
|
||||
return $dbQuery->take($limit)->get(['accounts.*']);
|
||||
}
|
||||
|
||||
public function searchAccountIncludingInactive(string $query, array $types, int $limit): Collection
|
||||
{
|
||||
$dbQuery = $this->user
|
||||
->accounts()
|
||||
->orderBy('accounts.order', 'ASC')
|
||||
->orderBy('accounts.account_type_id', 'ASC')
|
||||
->orderBy('accounts.name', 'ASC')
|
||||
->with(['accountType'])
|
||||
;
|
||||
if ('' !== $query) {
|
||||
// split query on spaces just in case:
|
||||
$parts = explode(' ', $query);
|
||||
foreach ($parts as $part) {
|
||||
$search = sprintf('%%%s%%', $part);
|
||||
$dbQuery->whereLike('name', $search);
|
||||
}
|
||||
}
|
||||
if (0 !== count($types)) {
|
||||
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$dbQuery->whereIn('account_types.type', $types);
|
||||
}
|
||||
|
||||
return $dbQuery->take($limit)->get(['accounts.*']);
|
||||
}
|
||||
|
||||
public function searchAccountNr(string $query, array $types, int $limit): Collection
|
||||
{
|
||||
$dbQuery = $this->user
|
||||
|
||||
@@ -156,6 +156,8 @@ interface AccountRepositoryInterface
|
||||
|
||||
public function searchAccount(string $query, array $types, int $limit): Collection;
|
||||
|
||||
public function searchAccountIncludingInactive(string $query, array $types, int $limit): Collection;
|
||||
|
||||
public function searchAccountNr(string $query, array $types, int $limit): Collection;
|
||||
|
||||
public function store(array $data): Account;
|
||||
|
||||
@@ -389,17 +389,13 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
|
||||
return (string) $budgetLimit->amount;
|
||||
}
|
||||
// if budget limit period is inside AB period, it can be added in full.
|
||||
if (!$limitPeriod->equals($availableBudgetPeriod) && $availableBudgetPeriod->contains($limitPeriod)) {
|
||||
if ($availableBudgetPeriod->contains($limitPeriod)) {
|
||||
Log::debug('This budget limit is smaller than the available budget period.');
|
||||
|
||||
return (string) $budgetLimit->amount;
|
||||
}
|
||||
|
||||
if (
|
||||
!$limitPeriod->equals($availableBudgetPeriod)
|
||||
&& !$availableBudgetPeriod->contains($limitPeriod)
|
||||
&& $availableBudgetPeriod->overlapsWith($limitPeriod)
|
||||
) {
|
||||
if ($availableBudgetPeriod->overlapsWith($limitPeriod)) {
|
||||
Log::debug('This budget limit is something else entirely!');
|
||||
$overlap = $availableBudgetPeriod->overlap($limitPeriod);
|
||||
if ($overlap instanceof Period) {
|
||||
|
||||
@@ -101,8 +101,12 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
'currency_code' => (string) $journal['currency_code'],
|
||||
'currency_decimal_places' => (int) $journal['currency_decimal_places'],
|
||||
'foreign_currency_id' => (int) ($journal['foreign_currency_id'] ?? 0),
|
||||
'foreign_amount' => isset($journal['foreign_amount']) ? Steam::negative((string) $journal['foreign_amount']) : null,
|
||||
'pc_amount' => isset($journal['pc_amount']) ? Steam::negative((string) $journal['pc_amount']) : null,
|
||||
'foreign_amount' => array_key_exists('foreign_amount', $journal) && null !== $journal['foreign_amount']
|
||||
? Steam::negative((string) $journal['foreign_amount'])
|
||||
: null,
|
||||
'pc_amount' => array_key_exists('pc_amount', $journal) && null !== $journal['pc_amount']
|
||||
? Steam::negative((string) $journal['pc_amount'])
|
||||
: null,
|
||||
'date' => $journal['date'],
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'budget_name' => $journal['budget_name'],
|
||||
@@ -186,8 +190,12 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
'currency_code' => (string) $journal['currency_code'],
|
||||
'currency_decimal_places' => (int) $journal['currency_decimal_places'],
|
||||
'foreign_currency_id' => (int) ($journal['foreign_currency_id'] ?? 0),
|
||||
'foreign_amount' => isset($journal['foreign_amount']) ? Steam::positive((string) $journal['foreign_amount']) : null,
|
||||
'pc_amount' => isset($journal['pc_amount']) ? Steam::positive((string) $journal['pc_amount']) : null,
|
||||
'foreign_amount' => array_key_exists('foreign_amount', $journal) && null !== $journal['foreign_amount']
|
||||
? Steam::positive((string) $journal['foreign_amount'])
|
||||
: null,
|
||||
'pc_amount' => array_key_exists('pc_amount', $journal) && null !== $journal['pc_amount']
|
||||
? Steam::positive((string) $journal['pc_amount'])
|
||||
: null,
|
||||
'date' => $journal['date'],
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'budget_name' => $journal['budget_name'],
|
||||
|
||||
@@ -253,10 +253,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
|
||||
// group has multiple members. How many are owner, except the user we're editing now?
|
||||
$ownerCount = $userGroup->groupMemberships()->where('user_role_id', $owner->id)->where('user_id', '!=', $user->id)->count();
|
||||
// if there are no other owners and the current users does not get or keep the owner role, refuse.
|
||||
if (
|
||||
0 === $ownerCount
|
||||
&& (0 === count($data['roles']) || count($data['roles']) > 0 && !in_array(UserRoleEnum::OWNER->value, $data['roles'], true))
|
||||
) {
|
||||
if (0 === $ownerCount && (0 === count($data['roles']) || !in_array(UserRoleEnum::OWNER->value, $data['roles'], true))) {
|
||||
Log::debug('User needs to keep owner role in this group, refuse to act');
|
||||
|
||||
throw new FireflyException('The last owner in this user group must keep the "owner" role.');
|
||||
|
||||
@@ -41,9 +41,6 @@ class IsValidAccountTypeList implements ValidationRule
|
||||
if (is_string($value)) {
|
||||
$values = explode(',', $value);
|
||||
}
|
||||
if (!is_array($values)) {
|
||||
$fail('validation.invalid_account_list')->translate();
|
||||
}
|
||||
$keys = array_keys($this->types);
|
||||
foreach ($values as $entry) {
|
||||
if (!in_array($entry, $keys, true)) {
|
||||
|
||||
@@ -41,9 +41,6 @@ class IsValidTransactionTypeList implements ValidationRule
|
||||
if (is_string($value)) {
|
||||
$values = explode(',', $value);
|
||||
}
|
||||
if (!is_array($values)) {
|
||||
$fail('validation.invalid_transaction_type_list')->translate();
|
||||
}
|
||||
$keys = array_keys($this->transactionTypes);
|
||||
foreach ($values as $entry) {
|
||||
if (!in_array($entry, $keys, true)) {
|
||||
|
||||
@@ -86,6 +86,8 @@ class AccountDestroyService
|
||||
foreach ($collection as $row) {
|
||||
if ((int) $row->the_count > 1) {
|
||||
$journalId = $row->transaction_journal_id;
|
||||
|
||||
/** @var null|TransactionJournal $journal */
|
||||
$journal = $user->transactionJournals()->find($journalId);
|
||||
if (null !== $journal) {
|
||||
Log::debug(sprintf('Deleted journal #%d because it has the same source as destination.', $journal->id));
|
||||
|
||||
@@ -144,15 +144,17 @@ class RemoteUserGuard implements Guard
|
||||
return $this->user?->id;
|
||||
}
|
||||
|
||||
public function setUser(Authenticatable|User|null $user): void
|
||||
public function setUser(Authenticatable|User|null $user): Guard
|
||||
{
|
||||
// Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
if ($user instanceof User) {
|
||||
$this->user = $user;
|
||||
|
||||
return;
|
||||
return $this;
|
||||
}
|
||||
Log::error(sprintf('Did not set user at %s', __METHOD__));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function user(): ?User
|
||||
|
||||
@@ -43,14 +43,12 @@ class BudgetList implements BinderInterface
|
||||
if ('allBudgets' === $value) {
|
||||
return auth()->user()->budgets()->where('active', true)->orderBy('order', 'ASC')->orderBy('name', 'ASC')->get();
|
||||
}
|
||||
|
||||
$list = array_unique(array_map(\intval(...), explode(',', $value)));
|
||||
|
||||
if (0 === count($list)) {
|
||||
if ('' === $value) {
|
||||
Log::warning('Budget list count is zero, return 404.');
|
||||
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$list = array_unique(array_map(\intval(...), explode(',', $value)));
|
||||
|
||||
/** @var Collection $collection */
|
||||
$collection = auth()->user()->budgets()->where('active', true)->whereIn('id', $list)->get();
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Binder;
|
||||
use FireflyIII\Models\Category;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
@@ -42,11 +43,12 @@ class CategoryList implements BinderInterface
|
||||
if ('allCategories' === $value) {
|
||||
return auth()->user()->categories()->orderBy('name', 'ASC')->get();
|
||||
}
|
||||
if ('' === $value) {
|
||||
Log::warning('Category list count is zero, return 404.');
|
||||
|
||||
$list = array_unique(array_map(\intval(...), explode(',', $value)));
|
||||
if (0 === count($list)) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$list = array_unique(array_map(\intval(...), explode(',', $value)));
|
||||
|
||||
/** @var Collection $collection */
|
||||
$collection = auth()->user()->categories()->whereIn('id', $list)->get();
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Binder;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
@@ -65,11 +66,12 @@ class JournalList implements BinderInterface
|
||||
|
||||
protected static function parseList(string $value): array
|
||||
{
|
||||
$list = array_unique(array_map(\intval(...), explode(',', $value)));
|
||||
if (0 === count($list)) {
|
||||
if ('' === $value) {
|
||||
Log::warning('Category list count is zero, return 404.');
|
||||
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
return $list;
|
||||
return array_unique(array_map(\intval(...), explode(',', $value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,15 +44,15 @@ class TagList implements BinderInterface
|
||||
if ('allTags' === $value) {
|
||||
return auth()->user()->tags()->orderBy('tag', 'ASC')->get();
|
||||
}
|
||||
$list = array_unique(array_map(\strtolower(...), explode(',', $value)));
|
||||
Log::debug('List of tags is', $list);
|
||||
|
||||
if (0 === count($list)) {
|
||||
Log::error('Tag list is empty.');
|
||||
if ('' === $value) {
|
||||
Log::warning('Category list count is zero, return 404.');
|
||||
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$list = array_unique(array_map(\strtolower(...), explode(',', $value)));
|
||||
Log::debug('List of tags is', $list);
|
||||
|
||||
/** @var TagRepositoryInterface $repository */
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
|
||||
@@ -89,16 +89,15 @@ trait ValidatesUserGroupTrait
|
||||
throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group'));
|
||||
}
|
||||
Log::debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title));
|
||||
$roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : [];
|
||||
if (0 === count($roles)) {
|
||||
if (0 === count($this->acceptedRoles)) {
|
||||
Log::debug('validateUserGroup: no roles defined, so no access.');
|
||||
|
||||
throw new AuthorizationException((string) trans('validation.no_accepted_roles_defined'));
|
||||
}
|
||||
Log::debug(sprintf('validateUserGroup: have %d roles to check.', count($roles)), $roles);
|
||||
Log::debug(sprintf('validateUserGroup: have %d roles to check.', count($this->acceptedRoles)), $this->acceptedRoles);
|
||||
|
||||
/** @var UserRoleEnum $role */
|
||||
foreach ($roles as $role) {
|
||||
foreach ($this->acceptedRoles as $role) {
|
||||
if ($user->hasRoleInGroupOrOwner($group, $role)) {
|
||||
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
|
||||
$this->userGroup = $group;
|
||||
|
||||
@@ -128,6 +128,12 @@ class BillDateCalculator
|
||||
}
|
||||
}
|
||||
Log::debug('end of loop');
|
||||
|
||||
/** @template T
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return null|T
|
||||
*/
|
||||
$simple = $set->map(static fn (Carbon $date) => $date->format('Y-m-d'));
|
||||
Log::debug(sprintf('Found %d pay dates', $set->count()), $simple->toArray());
|
||||
|
||||
|
||||
@@ -201,25 +201,25 @@ class Navigation
|
||||
Log::debug('endOfPeriod() requests "YTD" + future, set it to "3M" instead.');
|
||||
$repeatFreq = '3M';
|
||||
}
|
||||
|
||||
$new = Carbon::now();
|
||||
$functionMap = [
|
||||
'1D' => 'endOfDay',
|
||||
'daily' => 'endOfDay',
|
||||
'1W' => 'addWeek',
|
||||
'week' => 'addWeek',
|
||||
'weekly' => 'addWeek',
|
||||
'1M' => 'addMonth',
|
||||
'month' => 'addMonth',
|
||||
'monthly' => 'addMonth',
|
||||
'3M' => 'addQuarter',
|
||||
'quarter' => 'addQuarter',
|
||||
'quarterly' => 'addQuarter',
|
||||
'1W' => 'addWeeks',
|
||||
'week' => 'addWeeks',
|
||||
'weekly' => 'addWeeks',
|
||||
'1M' => 'addMonths',
|
||||
'month' => 'addMonths',
|
||||
'monthly' => 'addMonths',
|
||||
'3M' => 'addQuarters',
|
||||
'quarter' => 'addQuarters',
|
||||
'quarterly' => 'addQuarters',
|
||||
'6M' => 'addMonths',
|
||||
'half-year' => 'addMonths',
|
||||
'half_year' => 'addMonths',
|
||||
'year' => 'addYear',
|
||||
'yearly' => 'addYear',
|
||||
'1Y' => 'addYear',
|
||||
'year' => 'addYears',
|
||||
'yearly' => 'addYears',
|
||||
'1Y' => 'addYears',
|
||||
];
|
||||
$modifierMap = ['half-year' => 6, 'half_year' => 6, '6M' => 6];
|
||||
$subDay = ['week', 'weekly', '1W', 'month', 'monthly', '1M', '3M', 'quarter', 'quarterly', '6M', 'half-year', 'half_year', '1Y', 'year', 'yearly'];
|
||||
|
||||
@@ -45,8 +45,8 @@ trait ChecksLogin
|
||||
if (!$check) {
|
||||
return false;
|
||||
}
|
||||
if (!property_exists($this, 'acceptedRoles')) {
|
||||
Log::debug(sprintf('Request class %s has no acceptedRoles array', static::class));
|
||||
if (0 === count($this->acceptedRoles)) {
|
||||
Log::debug(sprintf('Request class %s has 0 entries in acceptedRoles array', static::class));
|
||||
|
||||
return true; // check for false already took place.
|
||||
}
|
||||
|
||||
@@ -205,10 +205,9 @@ trait ConvertsDataTypes
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
if (method_exists($this, 'validateUserGroup')) {
|
||||
$userGroup = $this->validateUserGroup($this);
|
||||
$repository->setUserGroup($userGroup);
|
||||
}
|
||||
// blindly assume this method exists.
|
||||
$userGroup = $this->validateUserGroup($this);
|
||||
$repository->setUserGroup($userGroup);
|
||||
|
||||
// set administration ID
|
||||
// group ID
|
||||
|
||||
@@ -487,7 +487,7 @@ class OperatorQuerySearch implements SearchInterface
|
||||
|
||||
// search direction: for destination accounts
|
||||
if (SearchDirection::DESTINATION === $searchDirection) { // destination
|
||||
// destination can be
|
||||
// the destination account can be
|
||||
$searchTypes = [
|
||||
AccountTypeEnum::ASSET->value,
|
||||
AccountTypeEnum::MORTGAGE->value,
|
||||
@@ -530,7 +530,7 @@ class OperatorQuerySearch implements SearchInterface
|
||||
}
|
||||
|
||||
// get accounts:
|
||||
$accounts = $this->accountRepository->searchAccount($value, $searchTypes, 1337);
|
||||
$accounts = $this->accountRepository->searchAccountIncludingInactive($value, $searchTypes, 1337);
|
||||
if (0 === $accounts->count() && false === $prohibited) {
|
||||
Log::warning('Found zero accounts, search for non existing account, NO results will be returned.');
|
||||
$this->collector->findNothing();
|
||||
|
||||
@@ -47,7 +47,6 @@ use Illuminate\Http\Middleware\HandleCors;
|
||||
use Illuminate\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||
use PragmaRX\Google2FALaravel\Middleware as MFAMiddleware;
|
||||
|
||||
/*
|
||||
@@ -63,19 +62,20 @@ use PragmaRX\Google2FALaravel\Middleware as MFAMiddleware;
|
||||
|
||||
bcscale(12);
|
||||
|
||||
if (!function_exists('envNonEmpty')) {
|
||||
if (!function_exists('envDefaultWhenEmpty')) {
|
||||
/**
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function envNonEmpty(string $key, string | int | bool | null $default = null)
|
||||
function envDefaultWhenEmpty(mixed $value, string | int | bool | null $default = null): mixed
|
||||
{
|
||||
$result = env($key, $default);
|
||||
if ('' === $result) {
|
||||
if(null === $value) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $result;
|
||||
if('' === $value) {
|
||||
return $default;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
84
composer.lock
generated
84
composer.lock
generated
@@ -6366,16 +6366,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/cache.git",
|
||||
"reference": "59184fa14658d7724cd9b8743d91c1b1aa618bff"
|
||||
"reference": "b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/cache/zipball/59184fa14658d7724cd9b8743d91c1b1aa618bff",
|
||||
"reference": "59184fa14658d7724cd9b8743d91c1b1aa618bff",
|
||||
"url": "https://api.github.com/repos/symfony/cache/zipball/b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f",
|
||||
"reference": "b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6442,7 +6442,7 @@
|
||||
"psr6"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/cache/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/cache/tree/v8.0.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6462,7 +6462,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-21T23:29:37+00:00"
|
||||
"time": "2026-03-06T13:17:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache-contracts",
|
||||
@@ -6619,16 +6619,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.4.6",
|
||||
"version": "v7.4.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "6d643a93b47398599124022eb24d97c153c12f27"
|
||||
"reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/6d643a93b47398599124022eb24d97c153c12f27",
|
||||
"reference": "6d643a93b47398599124022eb24d97c153c12f27",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d",
|
||||
"reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6693,7 +6693,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.4.6"
|
||||
"source": "https://github.com/symfony/console/tree/v7.4.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6713,7 +6713,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-25T17:02:47+00:00"
|
||||
"time": "2026-03-06T14:06:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
@@ -7231,16 +7231,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "f425139487f904e198f99e3c416c79ed08cef3c3"
|
||||
"reference": "ade9bd433450382f0af154661fc8e72758b4de36"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/f425139487f904e198f99e3c416c79ed08cef3c3",
|
||||
"reference": "f425139487f904e198f99e3c416c79ed08cef3c3",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/ade9bd433450382f0af154661fc8e72758b4de36",
|
||||
"reference": "ade9bd433450382f0af154661fc8e72758b4de36",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7303,7 +7303,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/http-client/tree/v8.0.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7323,7 +7323,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-20T07:51:53+00:00"
|
||||
"time": "2026-03-06T13:17:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@@ -7405,16 +7405,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.4.6",
|
||||
"version": "v7.4.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065"
|
||||
"reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/fd97d5e926e988a363cef56fbbf88c5c528e9065",
|
||||
"reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f94b3e7b7dafd40e666f0c9ff2084133bae41e81",
|
||||
"reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7463,7 +7463,7 @@
|
||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.4.6"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.4.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7483,20 +7483,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-21T16:25:55+00:00"
|
||||
"time": "2026-03-06T13:15:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v7.4.6",
|
||||
"version": "v7.4.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83"
|
||||
"reference": "3b3fcf386c809be990c922e10e4c620d6367cab1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/002ac0cf4cd972a7fd0912dcd513a95e8a81ce83",
|
||||
"reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3b3fcf386c809be990c922e10e4c620d6367cab1",
|
||||
"reference": "3b3fcf386c809be990c922e10e4c620d6367cab1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7582,7 +7582,7 @@
|
||||
"description": "Provides a structured process for converting a Request into a Response",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v7.4.6"
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v7.4.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7602,7 +7602,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-26T08:30:57+00:00"
|
||||
"time": "2026-03-06T16:33:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
@@ -7760,16 +7760,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.4.6",
|
||||
"version": "v7.4.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f"
|
||||
"reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/9fc881d95feae4c6c48678cb6372bd8a7ba04f5f",
|
||||
"reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1",
|
||||
"reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7825,7 +7825,7 @@
|
||||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.4.6"
|
||||
"source": "https://github.com/symfony/mime/tree/v7.4.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7845,7 +7845,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-05T15:57:06+00:00"
|
||||
"time": "2026-03-05T15:24:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -10373,16 +10373,16 @@
|
||||
},
|
||||
{
|
||||
"name": "driftingly/rector-laravel",
|
||||
"version": "2.1.11",
|
||||
"version": "2.1.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/driftingly/rector-laravel.git",
|
||||
"reference": "84ea7e03f4a2d9d33e303559ed7e3280bfdb8d01"
|
||||
"reference": "2a2175eefabca6d15c247d55de17c75dc2f787a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/84ea7e03f4a2d9d33e303559ed7e3280bfdb8d01",
|
||||
"reference": "84ea7e03f4a2d9d33e303559ed7e3280bfdb8d01",
|
||||
"url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/2a2175eefabca6d15c247d55de17c75dc2f787a9",
|
||||
"reference": "2a2175eefabca6d15c247d55de17c75dc2f787a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10403,9 +10403,9 @@
|
||||
"description": "Rector upgrades rules for Laravel Framework",
|
||||
"support": {
|
||||
"issues": "https://github.com/driftingly/rector-laravel/issues",
|
||||
"source": "https://github.com/driftingly/rector-laravel/tree/2.1.11"
|
||||
"source": "https://github.com/driftingly/rector-laravel/tree/2.1.12"
|
||||
},
|
||||
"time": "2026-03-05T19:46:28+00:00"
|
||||
"time": "2026-03-06T19:59:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ergebnis/phpstan-rules",
|
||||
|
||||
@@ -36,12 +36,12 @@ use Illuminate\Support\Facades\URL;
|
||||
use Spatie\Html\Facades\Html;
|
||||
|
||||
return [
|
||||
'name' => envNonEmpty('APP_NAME', 'Firefly III'),
|
||||
'env' => envNonEmpty('APP_ENV', 'production'),
|
||||
'name' => envDefaultWhenEmpty(env('APP_NAME'), 'Firefly III'),
|
||||
'env' => envDefaultWhenEmpty(env('APP_ENV'), 'production'),
|
||||
'debug' => env('APP_DEBUG', false),
|
||||
'url' => envNonEmpty('APP_URL', 'http://localhost'),
|
||||
'timezone' => envNonEmpty('TZ', 'UTC'),
|
||||
'locale' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'),
|
||||
'url' => envDefaultWhenEmpty(env('APP_URL'), 'http://localhost'),
|
||||
'timezone' => envDefaultWhenEmpty(env('TZ'), 'UTC'),
|
||||
'locale' => envDefaultWhenEmpty(env('DEFAULT_LANGUAGE'), 'en_US'),
|
||||
'fallback_locale' => 'en_US',
|
||||
'key' => env('APP_KEY'),
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
@@ -37,11 +37,11 @@ return [
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'guard' => envNonEmpty('AUTHENTICATION_GUARD', 'web'),
|
||||
'guard' => envDefaultWhenEmpty(env('AUTHENTICATION_GUARD'), 'web'),
|
||||
'passwords' => 'users',
|
||||
],
|
||||
'guard_header' => envNonEmpty('AUTHENTICATION_GUARD_HEADER', 'REMOTE_USER'),
|
||||
'guard_email' => envNonEmpty('AUTHENTICATION_GUARD_EMAIL'),
|
||||
'guard_header' => envDefaultWhenEmpty(env('AUTHENTICATION_GUARD_HEADER'), 'REMOTE_USER'),
|
||||
'guard_email' => env('AUTHENTICATION_GUARD_EMAIL'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -36,7 +36,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => envNonEmpty('CACHE_DRIVER', 'file'),
|
||||
'default' => envDefaultWhenEmpty(env('CACHE_DRIVER'), 'file'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -41,15 +41,15 @@ if (false !== $databaseUrl) {
|
||||
}
|
||||
|
||||
// Get SSL parameters from .env file.
|
||||
$mysql_ssl_ca_dir = envNonEmpty('MYSQL_SSL_CAPATH');
|
||||
$mysql_ssl_ca_file = envNonEmpty('MYSQL_SSL_CA');
|
||||
$mysql_ssl_cert = envNonEmpty('MYSQL_SSL_CERT');
|
||||
$mysql_ssl_key = envNonEmpty('MYSQL_SSL_KEY');
|
||||
$mysql_ssl_ciphers = envNonEmpty('MYSQL_SSL_CIPHER');
|
||||
$mysql_ssl_verify = envNonEmpty('MYSQL_SSL_VERIFY_SERVER_CERT');
|
||||
$mysql_ssl_ca_dir = env('MYSQL_SSL_CAPATH');
|
||||
$mysql_ssl_ca_file = env('MYSQL_SSL_CA');
|
||||
$mysql_ssl_cert = env('MYSQL_SSL_CERT');
|
||||
$mysql_ssl_key = env('MYSQL_SSL_KEY');
|
||||
$mysql_ssl_ciphers = env('MYSQL_SSL_CIPHER');
|
||||
$mysql_ssl_verify = env('MYSQL_SSL_VERIFY_SERVER_CERT');
|
||||
|
||||
$mySqlSSLOptions = [];
|
||||
$useSSL = envNonEmpty('MYSQL_USE_SSL', false);
|
||||
$useSSL = envDefaultWhenEmpty(env('MYSQL_USE_SSL'), false);
|
||||
if (false !== $useSSL && null !== $useSSL && '' !== $useSSL) {
|
||||
if (null !== $mysql_ssl_ca_dir) {
|
||||
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_CAPATH] = $mysql_ssl_ca_dir;
|
||||
@@ -72,19 +72,19 @@ if (false !== $useSSL && null !== $useSSL && '' !== $useSSL) {
|
||||
}
|
||||
|
||||
return [
|
||||
'default' => envNonEmpty('DB_CONNECTION', 'mysql'),
|
||||
'default' => envDefaultWhenEmpty(env('DB_CONNECTION'), 'mysql'),
|
||||
'connections' => [
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => envNonEmpty('DB_DATABASE', storage_path('database/database.sqlite')),
|
||||
'database' => envDefaultWhenEmpty(env('DB_DATABASE'), storage_path('database/database.sqlite')),
|
||||
'prefix' => '',
|
||||
],
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'host' => envNonEmpty('DB_HOST', $host),
|
||||
'port' => envNonEmpty('DB_PORT', $port),
|
||||
'database' => envNonEmpty('DB_DATABASE', $database),
|
||||
'username' => envNonEmpty('DB_USERNAME', $username),
|
||||
'host' => envDefaultWhenEmpty(env('DB_HOST'), $host),
|
||||
'port' => envDefaultWhenEmpty(env('DB_PORT'), $port),
|
||||
'database' => envDefaultWhenEmpty(env('DB_DATABASE'), $database),
|
||||
'username' => envDefaultWhenEmpty(env('DB_USERNAME'), $username),
|
||||
'password' => env('DB_PASSWORD', $password),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
@@ -96,19 +96,19 @@ return [
|
||||
],
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'host' => envNonEmpty('DB_HOST', $host),
|
||||
'port' => envNonEmpty('DB_PORT', $port),
|
||||
'database' => envNonEmpty('DB_DATABASE', $database),
|
||||
'username' => envNonEmpty('DB_USERNAME', $username),
|
||||
'host' => envDefaultWhenEmpty(env('DB_HOST'), $host),
|
||||
'port' => envDefaultWhenEmpty(env('DB_PORT'), $port),
|
||||
'database' => envDefaultWhenEmpty(env('DB_DATABASE'), $database),
|
||||
'username' => envDefaultWhenEmpty(env('DB_USERNAME'), $username),
|
||||
'password' => env('DB_PASSWORD', $password),
|
||||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'search_path' => envNonEmpty('PGSQL_SCHEMA', 'public'),
|
||||
'schema' => envNonEmpty('PGSQL_SCHEMA', 'public'),
|
||||
'sslmode' => envNonEmpty('PGSQL_SSL_MODE', 'prefer'),
|
||||
'sslcert' => envNonEmpty('PGSQL_SSL_CERT'),
|
||||
'sslkey' => envNonEmpty('PGSQL_SSL_KEY'),
|
||||
'sslrootcert' => envNonEmpty('PGSQL_SSL_ROOT_CERT'),
|
||||
'search_path' => envDefaultWhenEmpty(env('PGSQL_SCHEMA'), 'public'),
|
||||
'schema' => envDefaultWhenEmpty(env('PGSQL_SCHEMA'), 'public'),
|
||||
'sslmode' => envDefaultWhenEmpty(env('PGSQL_SSL_MODE'), 'prefer'),
|
||||
'sslcert' => env('PGSQL_SSL_CERT'),
|
||||
'sslkey' => env('PGSQL_SSL_KEY'),
|
||||
'sslrootcert' => env('PGSQL_SSL_ROOT_CERT'),
|
||||
],
|
||||
'sqlsrv' => [
|
||||
'driver' => 'sqlsrv',
|
||||
@@ -139,21 +139,21 @@ return [
|
||||
// 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'),
|
||||
],
|
||||
'default' => [
|
||||
'scheme' => envNonEmpty('REDIS_SCHEME', 'tcp'),
|
||||
'url' => envNonEmpty('REDIS_URL'),
|
||||
'path' => envNonEmpty('REDIS_PATH'),
|
||||
'host' => envNonEmpty('REDIS_HOST', '127.0.0.1'),
|
||||
'port' => envNonEmpty('REDIS_PORT', 6379),
|
||||
'scheme' => envDefaultWhenEmpty(env('REDIS_SCHEME'), 'tcp'),
|
||||
'url' => env('REDIS_URL'),
|
||||
'path' => env('REDIS_PATH'),
|
||||
'host' => envDefaultWhenEmpty(env('REDIS_HOST'), '127.0.0.1'),
|
||||
'port' => envDefaultWhenEmpty(env('REDIS_PORT'), 6379),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
'cache' => [
|
||||
'scheme' => envNonEmpty('REDIS_SCHEME', 'tcp'),
|
||||
'url' => envNonEmpty('REDIS_URL'),
|
||||
'path' => envNonEmpty('REDIS_PATH'),
|
||||
'host' => envNonEmpty('REDIS_HOST', '127.0.0.1'),
|
||||
'port' => envNonEmpty('REDIS_PORT', 6379),
|
||||
'scheme' => envDefaultWhenEmpty(env('REDIS_SCHEME'), 'tcp'),
|
||||
'url' => env('REDIS_URL'),
|
||||
'path' => env('REDIS_PATH'),
|
||||
'host' => envDefaultWhenEmpty(env('REDIS_HOST'), '127.0.0.1'),
|
||||
'port' => envDefaultWhenEmpty(env('REDIS_PORT'), 6379),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
|
||||
@@ -75,14 +75,20 @@ return [
|
||||
'webhooks' => true,
|
||||
'handle_debts' => true,
|
||||
'expression_engine' => true,
|
||||
'running_balance_column' => (bool)envNonEmpty('USE_RUNNING_BALANCE', true), // this is only the default value, is not used.
|
||||
'running_balance_column' => (bool)envDefaultWhenEmpty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used.
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => '6.5.4',
|
||||
'build_time' => 1772787852,
|
||||
'version' => 'develop/2026-03-06',
|
||||
'build_time' => 1772828124,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 28, // field is no longer used.
|
||||
|
||||
// Docker build info, if present:
|
||||
'is_docker' => env('IS_DOCKER', false),
|
||||
'base_image_build' => envDefaultWhenEmpty(env('BASE_IMAGE_BUILD'), '(unknown)'),
|
||||
'base_image_date' => envDefaultWhenEmpty(env('BASE_IMAGE_DATE'), '(unknown)'),
|
||||
'is_local_dev' => env('IS_LOCAL_DEV', false),
|
||||
|
||||
// generic settings
|
||||
'maxUploadSize' => 1073741824, // 1 GB
|
||||
'send_error_message' => env('SEND_ERROR_MESSAGE', true),
|
||||
@@ -91,7 +97,7 @@ return [
|
||||
// tokens and keys
|
||||
'fixer_api_key' => env('FIXER_API_KEY', ''),
|
||||
'ipinfo_token' => env('IPINFO_TOKEN', ''),
|
||||
'static_cron_token' => envNonEmpty('STATIC_CRON_TOKEN'),
|
||||
'static_cron_token' => env('STATIC_CRON_TOKEN'),
|
||||
|
||||
// flags
|
||||
'enable_external_map' => env('ENABLE_EXTERNAL_MAP', false), // no longer used, only for default.
|
||||
@@ -106,8 +112,8 @@ return [
|
||||
'tracker_url' => env('TRACKER_URL', ''),
|
||||
|
||||
// authentication settings
|
||||
'authentication_guard' => envNonEmpty('AUTHENTICATION_GUARD', 'web'),
|
||||
'custom_logout_url' => envNonEmpty('CUSTOM_LOGOUT_URL', ''),
|
||||
'authentication_guard' => envDefaultWhenEmpty(env('AUTHENTICATION_GUARD'), 'web'),
|
||||
'custom_logout_url' => envDefaultWhenEmpty(env('CUSTOM_LOGOUT_URL'), ''),
|
||||
|
||||
// static config (cannot be changed by user)
|
||||
'update_endpoint' => 'https://version.firefly-iii.org/index.json',
|
||||
@@ -188,8 +194,8 @@ return [
|
||||
'convertToPrimary' => false,
|
||||
],
|
||||
'default_currency' => 'EUR',
|
||||
'default_language' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'),
|
||||
'default_locale' => envNonEmpty('DEFAULT_LOCALE', 'equal'),
|
||||
'default_language' => envDefaultWhenEmpty(env('DEFAULT_LANGUAGE'), 'en_US'),
|
||||
'default_locale' => envDefaultWhenEmpty(env('DEFAULT_LOCALE'), 'equal'),
|
||||
|
||||
// account types that may have or set a currency
|
||||
'valid_currency_account_types' => [
|
||||
@@ -218,7 +224,7 @@ return [
|
||||
'available_dark_modes' => ['light', 'dark', 'browser'],
|
||||
'bill_reminder_periods' => [90, 30, 14, 7, 0],
|
||||
'valid_view_ranges' => ['1D', '1W', '1M', '3M', '6M', '1Y'],
|
||||
'valid_url_protocols' => envNonEmpty('VALID_URL_PROTOCOLS', 'http,https,ftp,ftps,mailto'), // no longer used, only for default.
|
||||
'valid_url_protocols' => envDefaultWhenEmpty(env('VALID_URL_PROTOCOLS'), 'http,https,ftp,ftps,mailto'), // no longer used, only for default.
|
||||
'allowedMimes' => [
|
||||
// plain files
|
||||
'text/plain',
|
||||
|
||||
@@ -34,8 +34,8 @@ $validChannels = ['single', 'papertrail', 'stdout', 'daily', 'syslog', 'err
|
||||
$validAuditChannels = ['audit_papertrail', 'audit_stdout', 'audit_stdout', 'audit_daily', 'audit_syslog', 'audit_errorlog'];
|
||||
|
||||
// which settings did the user set, if any?
|
||||
$defaultLogChannel = (string) envNonEmpty('LOG_CHANNEL', 'stack');
|
||||
$auditLogChannel = (string) envNonEmpty('AUDIT_LOG_CHANNEL', '');
|
||||
$defaultLogChannel = (string) envDefaultWhenEmpty(env('LOG_CHANNEL'), 'stack');
|
||||
$auditLogChannel = (string) env('AUDIT_LOG_CHANNEL');
|
||||
|
||||
if ('stack' === $defaultLogChannel) {
|
||||
$defaultChannels = ['daily', 'stdout'];
|
||||
@@ -60,8 +60,8 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => envNonEmpty('LOG_CHANNEL', 'stack'),
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'default' => envDefaultWhenEmpty(env('LOG_CHANNEL'), 'stack'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
@@ -93,11 +93,11 @@ return [
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_HOST'),
|
||||
@@ -107,21 +107,21 @@ return [
|
||||
'stdout' => [
|
||||
'driver' => 'single',
|
||||
'path' => 'php://stdout',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/ff3-'.PHP_SAPI.'.log'),
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
'days' => 7,
|
||||
],
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('APP_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -130,7 +130,7 @@ return [
|
||||
*/
|
||||
'audit_papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('AUDIT_LOG_LEVEL'), 'info'),
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
'tap' => [AuditLogger::class],
|
||||
'handler_with' => [
|
||||
@@ -142,24 +142,24 @@ return [
|
||||
'driver' => 'single',
|
||||
'path' => 'php://stdout',
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('AUDIT_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
'audit_daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/ff3-audit.log'),
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('AUDIT_LOG_LEVEL'), 'info'),
|
||||
'days' => 90,
|
||||
],
|
||||
'audit_syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('AUDIT_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
'audit_errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'level' => envDefaultWhenEmpty(env('AUDIT_LOG_LEVEL'), 'info'),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -34,16 +34,16 @@ return [
|
||||
| and used as needed; however, this mailer will be used by default.
|
||||
|
|
||||
*/
|
||||
'default' => envNonEmpty('MAIL_MAILER', 'log'),
|
||||
'default' => envDefaultWhenEmpty(env('MAIL_MAILER'), 'log'),
|
||||
|
||||
'mailers' => [
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'host' => envNonEmpty('MAIL_HOST', 'smtp.mailtrap.io'),
|
||||
'host' => envDefaultWhenEmpty(env('MAIL_HOST'), 'smtp.mailtrap.io'),
|
||||
'port' => (int) env('MAIL_PORT', 2525),
|
||||
'encryption' => envNonEmpty('MAIL_ENCRYPTION', 'tls'),
|
||||
'username' => envNonEmpty('MAIL_USERNAME', 'user@example.com'),
|
||||
'password' => envNonEmpty('MAIL_PASSWORD', 'password'),
|
||||
'encryption' => envDefaultWhenEmpty(env('MAIL_ENCRYPTION'), 'tls'),
|
||||
'username' => envDefaultWhenEmpty(env('MAIL_USERNAME'), 'user@example.com'),
|
||||
'password' => envDefaultWhenEmpty(env('MAIL_PASSWORD'), 'password'),
|
||||
'timeout' => null,
|
||||
'scheme' => env('MAIL_SCHEME'),
|
||||
'url' => env('MAIL_URL'),
|
||||
@@ -73,7 +73,7 @@ return [
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => envNonEmpty('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'),
|
||||
'path' => envDefaultWhenEmpty(env('MAIL_SENDMAIL_COMMAND'), '/usr/sbin/sendmail -bs'),
|
||||
],
|
||||
'log' => [
|
||||
'transport' => 'log',
|
||||
@@ -91,7 +91,7 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
'from' => ['address' => envNonEmpty('MAIL_FROM', 'changeme@example.com'), 'name' => 'Firefly III Mailer'],
|
||||
'from' => ['address' => envDefaultWhenEmpty(env('MAIL_FROM'), 'changeme@example.com'), 'name' => 'Firefly III Mailer'],
|
||||
'markdown' => [
|
||||
'theme' => 'default',
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => envNonEmpty('AUTHENTICATION_GUARD', 'web'),
|
||||
'guard' => envDefaultWhenEmpty(env('AUTHENTICATION_GUARD'), 'web'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
protected static function hasForeign(string $table, string $column): bool
|
||||
private static function hasForeign(string $table, string $column): bool
|
||||
{
|
||||
$foreignKeysDefinitions = Schema::getForeignKeys($table);
|
||||
foreach ($foreignKeysDefinitions as $foreignKeyDefinition) {
|
||||
|
||||
30
package-lock.json
generated
30
package-lock.json
generated
@@ -200,9 +200,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz",
|
||||
"integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==",
|
||||
"version": "0.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.7.tgz",
|
||||
"integrity": "sha512-6Fqi8MtQ/PweQ9xvux65emkLQ83uB+qAVtfHkC9UodyHMIZdxNI01HjLCLUtybElp2KY2XNE0nOgyP1E1vXw9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1586,13 +1586,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz",
|
||||
"integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==",
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.1.tgz",
|
||||
"integrity": "sha512-ENp89vM9Pw4kv/koBb5N2f9bDZsR0hpf3BdPMOg/pkS3pwO4dzNnQZVXtBbeyAadgm865DmQG2jMMLqmZXvuCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.6",
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.7",
|
||||
"core-js-compat": "^3.48.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -4055,14 +4055,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.4.15",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz",
|
||||
"integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==",
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.16.tgz",
|
||||
"integrity": "sha512-xaVwwSfebXf0ooE11BJovZYKhFjIvQo7TsyVpETuIeH2JHv0k/T6Y5j22pPTvqYqmpkxdlPAJlyJ0tfOJAoMxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.28.6",
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.6",
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.7",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -4094,13 +4094,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-regenerator": {
|
||||
"version": "0.6.6",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz",
|
||||
"integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==",
|
||||
"version": "0.6.7",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.7.tgz",
|
||||
"integrity": "sha512-OTYbUlSwXhNgr4g6efMZgsO8//jA61P7ZbRX3iTT53VON8l+WQS8IAUEVo4a4cWknrg2W8Cj4gQhRYNCJ8GkAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.6"
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
|
||||
Reference in New Issue
Block a user