diff --git a/.ci/php-cs-fixer/composer.lock b/.ci/php-cs-fixer/composer.lock index 1f30d2db98..2614d5842f 100644 --- a/.ci/php-cs-fixer/composer.lock +++ b/.ci/php-cs-fixer/composer.lock @@ -1331,16 +1331,16 @@ }, { "name": "symfony/console", - "version": "v8.1.2", + "version": "v8.1.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "535e18a1b8925f6c01a55b171d157ab66c2ace15" + "reference": "68efa2ebfd9a362951eb5a8b09fd177c66ddec24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/535e18a1b8925f6c01a55b171d157ab66c2ace15", - "reference": "535e18a1b8925f6c01a55b171d157ab66c2ace15", + "url": "https://api.github.com/repos/symfony/console/zipball/68efa2ebfd9a362951eb5a8b09fd177c66ddec24", + "reference": "68efa2ebfd9a362951eb5a8b09fd177c66ddec24", "shasum": "" }, "require": { @@ -1407,7 +1407,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v8.1.2" + "source": "https://github.com/symfony/console/tree/v8.1.4" }, "funding": [ { @@ -1427,7 +1427,7 @@ "type": "tidelift" } ], - "time": "2026-07-27T13:58:19+00:00" + "time": "2026-07-31T12:43:13+00:00" }, { "name": "symfony/deprecation-contracts", diff --git a/app/Api/V1/Controllers/Insight/Income/TagController.php b/app/Api/V1/Controllers/Insight/Income/TagController.php index 94be2ae461..df99eef909 100644 --- a/app/Api/V1/Controllers/Insight/Income/TagController.php +++ b/app/Api/V1/Controllers/Insight/Income/TagController.php @@ -158,10 +158,7 @@ final class TagController extends Controller 'currency_id' => (string) $foreignCurrencyId, 'currency_code' => $journal['foreign_currency_code'], ]; - $response[$foreignKey]['difference'] = bcadd( - (string) $response[$foreignKey]['difference'], - Steam::positive($journal['foreign_amount']) - ); + $response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount'])); $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; } } diff --git a/app/Api/V1/Controllers/Insight/Transfer/TagController.php b/app/Api/V1/Controllers/Insight/Transfer/TagController.php index b7b85fd376..f92a7aa9f0 100644 --- a/app/Api/V1/Controllers/Insight/Transfer/TagController.php +++ b/app/Api/V1/Controllers/Insight/Transfer/TagController.php @@ -155,10 +155,7 @@ final class TagController extends Controller 'currency_id' => (string) $foreignCurrencyId, 'currency_code' => $journal['foreign_currency_code'], ]; - $response[$foreignKey]['difference'] = bcadd( - (string) $response[$foreignKey]['difference'], - Steam::positive($journal['foreign_amount']) - ); + $response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount'])); $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float } } diff --git a/app/Exceptions/GracefulNotFoundHandler.php b/app/Exceptions/GracefulNotFoundHandler.php index 7339838641..741e900fd4 100644 --- a/app/Exceptions/GracefulNotFoundHandler.php +++ b/app/Exceptions/GracefulNotFoundHandler.php @@ -63,6 +63,7 @@ class GracefulNotFoundHandler extends ExceptionHandler if (!auth()->check()) { return parent::render($request, $e); } + switch ($name) { default: Log::warning(sprintf('GracefulNotFoundHandler cannot handle route with name "%s"', $name)); @@ -261,6 +262,7 @@ class GracefulNotFoundHandler extends ExceptionHandler if (TransactionTypeEnum::RECONCILIATION->value === $type) { session()->flash('info', trans('errors.note_not_found_reconciliation', ['description' => $group->title ?? $journal->description])); + return redirect(route('accounts.index', ['asset'])); } session()->flash('info', trans('errors.note_not_found_group', ['description' => $group->title ?? $journal->description])); diff --git a/app/Http/Controllers/Account/CreateController.php b/app/Http/Controllers/Account/CreateController.php index bb7a4dd3e9..eac446fe15 100644 --- a/app/Http/Controllers/Account/CreateController.php +++ b/app/Http/Controllers/Account/CreateController.php @@ -44,7 +44,7 @@ final class CreateController extends Controller { use ModelInformation; - private AttachmentHelperInterface $attachments; + private AttachmentHelperInterface $attachments; private AccountRepositoryInterface $repository; /** @@ -57,7 +57,7 @@ final class CreateController extends Controller // translations: $this->middleware(function ($request, $next) { app('view')->share('mainTitleIcon', 'bi-credit-card'); - app('view')->share('title', (string)trans('firefly.accounts')); + app('view')->share('title', (string) trans('firefly.accounts')); $this->repository = app(AccountRepositoryInterface::class); $this->attachments = app(AttachmentHelperInterface::class); @@ -71,12 +71,12 @@ final class CreateController extends Controller * * @return Factory|View */ - public function create(Request $request, string $objectType): Factory | \Illuminate\Contracts\View\View + public function create(Request $request, string $objectType): Factory|\Illuminate\Contracts\View\View { $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType)); - $subTitle = (string)trans(sprintf('firefly.make_new_%s_account', $objectType)); + $subTitle = (string) trans(sprintf('firefly.make_new_%s_account', $objectType)); $roles = $this->getRoles(); - $from = $request->input('_from', ''); + $from = $request->input('_from', ''); $liabilityTypes = $this->getLiabilityTypes(); $hasOldInput = null !== $request->old('_token'); $locations = [ @@ -90,7 +90,7 @@ final class CreateController extends Controller $liabilityDirections = ['debit' => trans('firefly.liability_direction_debit'), 'credit' => trans('firefly.liability_direction_credit')]; // interest calculation periods: - $interestPeriods = []; + $interestPeriods = []; foreach (config('firefly.interest_periods') as $period) { $interestPeriods[$period] = trans(sprintf('firefly.interest_calc_%s', $period)); } @@ -98,10 +98,10 @@ final class CreateController extends Controller // prefill some data $request->session()->flash('preFilled', [ 'currency_id' => $this->primaryCurrency->id, - 'include_net_worth' => !$hasOldInput || (bool)$request->old('include_net_worth'), + 'include_net_worth' => !$hasOldInput || (bool) $request->old('include_net_worth'), ]); // issue #8321 - $showNetWorth = true; + $showNetWorth = true; if ('liabilities' !== $objectType && 'asset' !== $objectType) { $showNetWorth = false; } @@ -129,9 +129,9 @@ final class CreateController extends Controller public function store(AccountFormRequest $request): RedirectResponse { - $data = $request->getAccountData(); - $account = $this->repository->store($data); - $request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name])); + $data = $request->getAccountData(); + $account = $this->repository->store($data); + $request->session()->flash('success', (string) trans('firefly.stored_new_account', ['name' => $account->name])); Preferences::mark(); Log::channel('audit')->info('Stored new account.', $data); @@ -148,13 +148,13 @@ final class CreateController extends Controller // store attachment(s): /** @var null|array $files */ - $files = $request->hasFile('attachments') ? $request->file('attachments') : null; + $files = $request->hasFile('attachments') ? $request->file('attachments') : null; if (null !== $files && !auth()->user()->hasRole('demo')) { $this->attachments->saveAttachmentsForModel($account, $files); } if (null !== $files && auth()->user()->hasRole('demo')) { Log::channel('audit')->warning(sprintf('The demo user is trying to upload attachments in %s.', __METHOD__)); - session()->flash('info', (string)trans('firefly.no_att_demo_user')); + session()->flash('info', (string) trans('firefly.no_att_demo_user')); } if (count($this->attachments->getMessages()->get('attachments')) > 0) { @@ -162,9 +162,9 @@ final class CreateController extends Controller } // redirect to previous URL. - $from = $request->input('_from', ''); - $redirect = redirect(route('index') . $from); - if (1 === (int)$request->input('create_another')) { + $from = $request->input('_from', ''); + $redirect = redirect(route('index').$from); + if (1 === (int) $request->input('create_another')) { // set value so create routine will not overwrite URL: $request->session()->put('accounts.create.fromStore', true); diff --git a/app/Http/Controllers/Account/EditController.php b/app/Http/Controllers/Account/EditController.php index 3cb8a3b3bf..e4b95ed447 100644 --- a/app/Http/Controllers/Account/EditController.php +++ b/app/Http/Controllers/Account/EditController.php @@ -84,7 +84,7 @@ final class EditController extends Controller if (!$this->isEditableAccount($account)) { return $this->redirectAccountToAccount($account); } - $from = $request->input('_from', ''); + $from = $request->input('_from', ''); $objectType = config('firefly.shortNamesByFullName')[$account->accountType->type]; $subTitle = (string) trans(sprintf('firefly.edit_%s_account', $objectType), ['name' => $account->name]); $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType)); @@ -165,7 +165,7 @@ final class EditController extends Controller $request->session()->flash('preFilled', $preFilled); return view('accounts.edit', [ - 'from'=>$from, + 'from' => $from, 'account' => $account, 'currency' => $currency, 'canEditCurrency' => $canEditCurrency, @@ -214,8 +214,9 @@ final class EditController extends Controller } // redirect - $from = $request->input('_from', ''); - $redirect = redirect(route('index') . $from);; + $from = $request->input('_from', ''); + $redirect = redirect(route('index').$from); + if (1 === (int) $request->input('return_to_edit')) { // set value so edit routine will not overwrite URL: $request->session()->put('accounts.edit.fromUpdate', true); diff --git a/app/Http/Controllers/Budget/BudgetLimitController.php b/app/Http/Controllers/Budget/BudgetLimitController.php index 04d75cd738..de7337738f 100644 --- a/app/Http/Controllers/Budget/BudgetLimitController.php +++ b/app/Http/Controllers/Budget/BudgetLimitController.php @@ -198,13 +198,7 @@ final class BudgetLimitController extends Controller if ($request->expectsJson()) { $array = $limit->toArray(); // add some extra metadata: - $spentArr = $this->opsRepository->sumExpenses( - $limit->start_date, - $limit->end_date, - null, - new Collection()->push($budget), - $currency - ); + $spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection()->push($budget), $currency); $array['spent'] = $spentArr[$currency->id]['sum'] ?? '0'; $array['left_formatted'] = Amount::formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount'])); $array['amount_formatted'] = Amount::formatAnything($limit->transactionCurrency, $limit['amount']); diff --git a/app/Http/Controllers/Budget/IndexController.php b/app/Http/Controllers/Budget/IndexController.php index d40d4432a3..215ebbd484 100644 --- a/app/Http/Controllers/Budget/IndexController.php +++ b/app/Http/Controllers/Budget/IndexController.php @@ -284,10 +284,7 @@ final class IndexController extends Controller if (array_key_exists($currency->id, $spentArr) && array_key_exists('sum', $spentArr[$currency->id])) { $array['spent'][$currency->id]['spent'] = $spentArr[$currency->id]['sum']; - $array['spent'][$currency->id]['spent_outside'] = Steam::negative(bcsub( - $spentInLimits[$currency->id], - $spentArr[$currency->id]['sum'] - )); + $array['spent'][$currency->id]['spent_outside'] = Steam::negative(bcsub($spentInLimits[$currency->id], $spentArr[$currency->id]['sum'])); $array['spent'][$currency->id]['currency_id'] = $currency->id; $array['spent'][$currency->id]['currency_symbol'] = $currency->symbol; $array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places; diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index f4b32fe5c5..ad724137dc 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -539,13 +539,7 @@ final class BudgetController extends Controller } // get spent amount in this period for this currency. - $sum = $this->opsRepository->sumExpenses( - $currentStart, - $currentEnd, - $accounts, - new Collection()->push($budget), - $currency - ); + $sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency); $amount = Steam::positive($sum[$currency->id]['sum'] ?? '0'); $chartData[0]['entries'][$title] = Steam::bcround($amount, $currency->decimal_places); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 787f6f5c16..7ba3b2db5d 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -41,9 +41,10 @@ use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\View; + use function Safe\ini_get; -use function Safe\realpath; use function Safe\parse_url; +use function Safe\realpath; /** * Class Controller. @@ -60,13 +61,13 @@ abstract class Controller extends BaseController use ValidatesRequests; // fails on PHP < 8.4 - public protected(set) string $name; - protected bool $convertToPrimary = false; - protected string $dateTimeFormat; + public protected(set) string $name; + protected bool $convertToPrimary = false; + protected string $dateTimeFormat; protected ?TransactionCurrency $primaryCurrency; - protected string $monthAndDayFormat; - protected string $monthFormat; - protected string $redirectUrl = '/'; + protected string $monthAndDayFormat; + protected string $monthFormat; + protected string $redirectUrl = '/'; /** * Controller constructor. @@ -82,7 +83,7 @@ abstract class Controller extends BaseController return; } - $isDemoSite = (bool)$isDemoSiteConfig->data; + $isDemoSite = (bool) $isDemoSiteConfig->data; View::share('IS_DEMO_SITE', $isDemoSite); View::share('DEMO_USERNAME', config('firefly.demo_username')); View::share('DEMO_PASSWORD', config('firefly.demo_password')); @@ -90,12 +91,12 @@ abstract class Controller extends BaseController View::share('FF_BUILD_TIME', config('firefly.build_time')); View::share('FF3_FROM', $this->getFromUrl()); // this breaks when running < PHP 8.5 and is totally intentional. - $input = ' James is cool'; - $output = $input - |> trim(...) - |> (fn(string $string) => str_replace(' ', '-', $string)) - |> (fn(string $string) => str_replace(['.', '/', '…'], '', $string)) - |> strtolower(...); + $input = ' James is cool'; + $output = $input + |> trim(...) + |> (fn (string $string) => str_replace(' ', '-', $string)) + |> (fn (string $string) => str_replace(['.', '/', '…'], '', $string)) + |> strtolower(...); // is webhooks enabled? View::share( @@ -106,8 +107,8 @@ abstract class Controller extends BaseController View::share('featuringCer', true === AppConfiguration::get('enable_exchange_rates', config('cer.enabled'))->data); // share custom auth guard info. - $authGuard = config('firefly.authentication_guard'); - $logoutUrl = config('firefly.custom_logout_url'); + $authGuard = config('firefly.authentication_guard'); + $logoutUrl = config('firefly.custom_logout_url'); // overrule v2 layout back to v1. @@ -127,17 +128,17 @@ abstract class Controller extends BaseController View::share('uploadSize', $uploadSize); // share is alpha, is beta - $isAlpha = false; - $isBeta = false; - $isDevelop = false; - if (str_contains((string)config('firefly.version'), 'alpha')) { + $isAlpha = false; + $isBeta = false; + $isDevelop = false; + if (str_contains((string) config('firefly.version'), 'alpha')) { $isAlpha = true; } - if (str_contains((string)config('firefly.version'), 'develop') || str_contains((string)config('firefly.version'), 'branch')) { + if (str_contains((string) config('firefly.version'), 'develop') || str_contains((string) config('firefly.version'), 'branch')) { $isDevelop = true; } - if (str_contains((string)config('firefly.version'), 'beta')) { + if (str_contains((string) config('firefly.version'), 'beta')) { $isBeta = true; } @@ -146,11 +147,11 @@ abstract class Controller extends BaseController View::share('FF_IS_DEVELOP', $isDevelop); $this->middleware(function ($request, $next): mixed { - $locale = Steam::getLocale(); + $locale = Steam::getLocale(); // translations for specific strings: - $this->monthFormat = (string)trans('config.month_js', [], $locale); - $this->monthAndDayFormat = (string)trans('config.month_and_day_js', [], $locale); - $this->dateTimeFormat = (string)trans('config.date_time_js', [], $locale); + $this->monthFormat = (string) trans('config.month_js', [], $locale); + $this->monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale); + $this->dateTimeFormat = (string) trans('config.date_time_js', [], $locale); $darkMode = 'browser'; $this->primaryCurrency = null; // get shown-intro-preference: @@ -191,12 +192,13 @@ abstract class Controller extends BaseController if (array_key_exists('path', $current)) { $from = $current['path']; } - if (array_key_exists('query', $current) && strlen($current['query']) > 0) { - $from .= '?' . $current['query']; + if (array_key_exists('query', $current) && '' !== $current['query']) { + $from .= '?'.$current['query']; } - if (array_key_exists('fragment', $current) && strlen($current['fragment']) > 0) { - $from .= '#' . $current['fragment']; + if (array_key_exists('fragment', $current) && '' !== $current['fragment']) { + $from .= '#'.$current['fragment']; } + return $from; } } diff --git a/app/Http/Requests/AccountFormRequest.php b/app/Http/Requests/AccountFormRequest.php index 8f3dbc583f..0690053481 100644 --- a/app/Http/Requests/AccountFormRequest.php +++ b/app/Http/Requests/AccountFormRequest.php @@ -121,7 +121,7 @@ class AccountFormRequest extends FormRequest 'what' => 'in:'.$types, 'interest_period' => 'in:daily,monthly,yearly', 'notes' => ['min:1', 'max:32768', 'nullable'], - '_from' => ['string','min:0','max:255', new IsValidOriginUrl()], + '_from' => ['string', 'min:0', 'max:255', new IsValidOriginUrl()], ]; $rules = Location::requestRules($rules); diff --git a/app/Jobs/CreateAutoBudgetLimits.php b/app/Jobs/CreateAutoBudgetLimits.php index d61661dd50..93cf5e9364 100644 --- a/app/Jobs/CreateAutoBudgetLimits.php +++ b/app/Jobs/CreateAutoBudgetLimits.php @@ -122,13 +122,7 @@ class CreateAutoBudgetLimits implements ShouldQueue // if has one, calculate expenses and use that as a base. $repository = app(OperationsRepositoryInterface::class); $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses( - $previousStart, - $previousEnd, - null, - new Collection()->push($autoBudget->budget), - $autoBudget->transactionCurrency - ); + $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency); $currencyId = $autoBudget->transaction_currency_id; $spentAmount = $spent[$currencyId]['sum'] ?? '0'; Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); @@ -218,13 +212,7 @@ class CreateAutoBudgetLimits implements ShouldQueue // if has one, calculate expenses and use that as a base. $repository = app(OperationsRepositoryInterface::class); $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses( - $previousStart, - $previousEnd, - null, - new Collection()->push($autoBudget->budget), - $autoBudget->transactionCurrency - ); + $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency); $currencyId = $autoBudget->transaction_currency_id; $spentAmount = $spent[$currencyId]['sum'] ?? '0'; Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); diff --git a/app/Models/Account.php b/app/Models/Account.php index f682e9efaa..746592af6c 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -63,7 +63,7 @@ class Account extends Model /** * Route binder. Converts the key in the URL to the specified object (or throw 404). * - * @throws NotFoundHttpException|AuthenticationException + * @throws AuthenticationException|NotFoundHttpException */ public static function routeBinder(self|string $value): self { @@ -81,6 +81,7 @@ class Account extends Model if (null !== $account) { return $account; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Attachment.php b/app/Models/Attachment.php index e91c4c73ba..a47fab6df0 100644 --- a/app/Models/Attachment.php +++ b/app/Models/Attachment.php @@ -79,6 +79,7 @@ class Attachment extends Model if (null !== $attachment) { return $attachment; } + throw new NotFoundHttpException(); } diff --git a/app/Models/AvailableBudget.php b/app/Models/AvailableBudget.php index 185addadd6..dae5b7fa0f 100644 --- a/app/Models/AvailableBudget.php +++ b/app/Models/AvailableBudget.php @@ -80,6 +80,7 @@ class AvailableBudget extends Model if (null !== $availableBudget) { return $availableBudget; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Bill.php b/app/Models/Bill.php index 410735eaf1..b1945fb695 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -99,6 +99,7 @@ class Bill extends Model if (null !== $bill) { return $bill; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Budget.php b/app/Models/Budget.php index efb53d79da..b212fcb6eb 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -67,6 +67,7 @@ class Budget extends Model if (null !== $budget) { return $budget; } + throw new NotFoundHttpException(); } diff --git a/app/Models/BudgetLimit.php b/app/Models/BudgetLimit.php index a6db0f9e38..335299d42b 100644 --- a/app/Models/BudgetLimit.php +++ b/app/Models/BudgetLimit.php @@ -69,6 +69,7 @@ class BudgetLimit extends Model if (null !== $budgetLimit) { return $budgetLimit; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Category.php b/app/Models/Category.php index 272f4b5712..6a655e1ffe 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -69,6 +69,7 @@ class Category extends Model if (null !== $category) { return $category; } + throw new NotFoundHttpException(); } diff --git a/app/Models/InvitedUser.php b/app/Models/InvitedUser.php index edbb7b4fc1..41edac8054 100644 --- a/app/Models/InvitedUser.php +++ b/app/Models/InvitedUser.php @@ -60,6 +60,7 @@ class InvitedUser extends Model if (null !== $attempt) { return $attempt; } + throw new NotFoundHttpException(); } diff --git a/app/Models/LinkType.php b/app/Models/LinkType.php index fa12b2ef51..2326e1fc3d 100644 --- a/app/Models/LinkType.php +++ b/app/Models/LinkType.php @@ -53,6 +53,7 @@ class LinkType extends Model if (null !== $linkType) { return $linkType; } + throw new NotFoundHttpException(); } diff --git a/app/Models/ObjectGroup.php b/app/Models/ObjectGroup.php index d072a39a9d..2d5c4f824c 100644 --- a/app/Models/ObjectGroup.php +++ b/app/Models/ObjectGroup.php @@ -59,6 +59,7 @@ class ObjectGroup extends Model if (null !== $objectGroup) { return $objectGroup; } + throw new NotFoundHttpException(); } diff --git a/app/Models/PiggyBank.php b/app/Models/PiggyBank.php index 78d40432b0..c91445aae9 100644 --- a/app/Models/PiggyBank.php +++ b/app/Models/PiggyBank.php @@ -83,6 +83,7 @@ class PiggyBank extends Model if (null !== $piggyBank) { return $piggyBank; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Preference.php b/app/Models/Preference.php index 238e4b1c3d..00eb677000 100644 --- a/app/Models/Preference.php +++ b/app/Models/Preference.php @@ -95,6 +95,7 @@ class Preference extends Model return $preference; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Recurrence.php b/app/Models/Recurrence.php index 521e6c9cb9..c2cfd32a62 100644 --- a/app/Models/Recurrence.php +++ b/app/Models/Recurrence.php @@ -93,6 +93,7 @@ class Recurrence extends Model if (null !== $recurrence) { return $recurrence; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Rule.php b/app/Models/Rule.php index 8a6f13d128..7485c8eefc 100644 --- a/app/Models/Rule.php +++ b/app/Models/Rule.php @@ -71,6 +71,7 @@ class Rule extends Model if (null !== $rule) { return $rule; } + throw new NotFoundHttpException(); } diff --git a/app/Models/RuleGroup.php b/app/Models/RuleGroup.php index 41ed0aa8d7..2be62b2a79 100644 --- a/app/Models/RuleGroup.php +++ b/app/Models/RuleGroup.php @@ -71,6 +71,7 @@ class RuleGroup extends Model if (null !== $ruleGroup) { return $ruleGroup; } + throw new NotFoundHttpException(); } diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 35d50ab4b6..b14a05815c 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -73,6 +73,7 @@ class Tag extends Model if (null !== $tag) { return $tag; } + throw new NotFoundHttpException(); } diff --git a/app/Models/TransactionCurrency.php b/app/Models/TransactionCurrency.php index ad37f71f9f..5c0ba14f3e 100644 --- a/app/Models/TransactionCurrency.php +++ b/app/Models/TransactionCurrency.php @@ -63,6 +63,7 @@ class TransactionCurrency extends Model return $currency; } + throw new NotFoundHttpException(); } diff --git a/app/Models/TransactionJournal.php b/app/Models/TransactionJournal.php index 9bd50919da..b1ebd93356 100644 --- a/app/Models/TransactionJournal.php +++ b/app/Models/TransactionJournal.php @@ -110,6 +110,7 @@ class TransactionJournal extends Model if (null !== $journal) { return $journal; } + throw new NotFoundHttpException(); } diff --git a/app/Models/TransactionJournalLink.php b/app/Models/TransactionJournalLink.php index 75225ec22d..92c1cdb136 100644 --- a/app/Models/TransactionJournalLink.php +++ b/app/Models/TransactionJournalLink.php @@ -60,6 +60,7 @@ class TransactionJournalLink extends Model if (null !== $link) { return $link; } + throw new NotFoundHttpException(); } diff --git a/app/Models/WebhookAttempt.php b/app/Models/WebhookAttempt.php index 0c15d97b89..5351356496 100644 --- a/app/Models/WebhookAttempt.php +++ b/app/Models/WebhookAttempt.php @@ -59,6 +59,7 @@ class WebhookAttempt extends Model if (null !== $attempt && $attempt->webhookMessage->webhook->user_id === $user->id) { return $attempt; } + throw new NotFoundHttpException(); } diff --git a/app/Models/WebhookMessage.php b/app/Models/WebhookMessage.php index 8d77ac76b5..c64e0bb527 100644 --- a/app/Models/WebhookMessage.php +++ b/app/Models/WebhookMessage.php @@ -64,6 +64,7 @@ class WebhookMessage extends Model if (null !== $message && $message->webhook->user_id === $user->id) { return $message; } + throw new NotFoundHttpException(); } diff --git a/app/Rules/System/IsValidOriginUrl.php b/app/Rules/System/IsValidOriginUrl.php index 9cdb603e4c..c1a73f97f9 100644 --- a/app/Rules/System/IsValidOriginUrl.php +++ b/app/Rules/System/IsValidOriginUrl.php @@ -1,4 +1,7 @@ check()) { - $fail('validation.no_auth_present')->translate(); + $fail('validation.no_auth_present')->translate(); return; } - $value = (string)$value; - if(str_contains($value, '%2F')) { + $value = (string) $value; + if (str_contains($value, '%2F')) { $value = urldecode($value); } - if('' === $value) { + if ('' === $value) { // string can be empty. return; } + try { $parts = parse_url($value); } catch (UrlException) { @@ -52,12 +57,14 @@ class IsValidOriginUrl implements ValidationRule return; } - if(!array_key_exists('path', $parts) || array_key_exists('scheme', $parts) || array_key_exists('host', $parts)) { + if (!array_key_exists('path', $parts) || array_key_exists('scheme', $parts) || array_key_exists('host', $parts)) { $fail('validation.bad_url_parts')->translate(); + return; } - if(!str_starts_with($parts['path'], '/')) { + if (!str_starts_with($parts['path'], '/')) { $fail('validation.bad_url_parts')->translate(); + // return; } } diff --git a/app/Support/Http/Controllers/AugumentData.php b/app/Support/Http/Controllers/AugumentData.php index a507156873..a3a940b1ba 100644 --- a/app/Support/Http/Controllers/AugumentData.php +++ b/app/Support/Http/Controllers/AugumentData.php @@ -222,14 +222,7 @@ trait AugumentData $currentEnd->addMonth(); } // primary currency amount. - $expenses = $opsRepository->sumExpenses( - $currentStart, - $currentEnd, - null, - $budgetCollection, - $entry->transactionCurrency, - $this->convertToPrimary - ); + $expenses = $opsRepository->sumExpenses($currentStart, $currentEnd, null, $budgetCollection, $entry->transactionCurrency, $this->convertToPrimary); $spent = $expenses[$currency->id]['sum'] ?? '0'; $entry->pc_spent = $spent; diff --git a/app/Support/JsonApi/Enrichments/RecurringEnrichment.php b/app/Support/JsonApi/Enrichments/RecurringEnrichment.php index 2428353cb0..d0c09bf027 100644 --- a/app/Support/JsonApi/Enrichments/RecurringEnrichment.php +++ b/app/Support/JsonApi/Enrichments/RecurringEnrichment.php @@ -354,11 +354,7 @@ class RecurringEnrichment implements EnrichmentInterface /** @var RecurrenceRepetition $repetition */ foreach ($set as $repetition) { - $recurrence = $this->collection->filter( - static fn (Recurrence $item): bool => (int) $item->id === (int) $repetition->recurrence_id - ) - ->first() - ; + $recurrence = $this->collection->filter(static fn (Recurrence $item): bool => (int) $item->id === (int) $repetition->recurrence_id)->first(); $fromDate = clone ($recurrence->latest_date ?? $recurrence->first_date); $recurrenceId = (int) $repetition->recurrence_id; $repId = (int) $repetition->id; diff --git a/app/User.php b/app/User.php index 8b4aa0f9d1..16c8e82c0a 100644 --- a/app/User.php +++ b/app/User.php @@ -102,6 +102,7 @@ class User extends Authenticatable implements OAuthenticatable if (null !== $user) { return $user; } + throw new NotFoundHttpException(); } diff --git a/composer.lock b/composer.lock index 328be2ac19..c8d400a7a8 100644 --- a/composer.lock +++ b/composer.lock @@ -2508,16 +2508,16 @@ }, { "name": "league/commonmark", - "version": "2.9.0", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "5703d83ba3da3b2e356a5fedc848ed6d8ffb6529" + "reference": "73cb188c785abfa7a7bec73487148202968274c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/5703d83ba3da3b2e356a5fedc848ed6d8ffb6529", - "reference": "5703d83ba3da3b2e356a5fedc848ed6d8ffb6529", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/73cb188c785abfa7a7bec73487148202968274c6", + "reference": "73cb188c785abfa7a7bec73487148202968274c6", "shasum": "" }, "require": { @@ -2611,7 +2611,7 @@ "type": "tidelift" } ], - "time": "2026-08-03T13:42:31+00:00" + "time": "2026-08-09T14:10:38+00:00" }, { "name": "league/config", diff --git a/config/firefly.php b/config/firefly.php index c44717febf..e1010b35a9 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -78,8 +78,8 @@ return [ 'running_balance_column' => (bool)env_default_when_empty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used. // see cer.php for exchange rates feature flag. ], -'version' => 'develop/2026-08-07', -'build_time' => 1786105226, +'version' => 'develop/2026-08-09', +'build_time' => 1786295232, 'api_version' => '2.1.0', // field is no longer used. 'db_version' => 28, // field is no longer used. diff --git a/package-lock.json b/package-lock.json index 6cceeef607..0755d875f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2701,9 +2701,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.1.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", - "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", "dev": true, "license": "MIT", "dependencies": { @@ -3499,9 +3499,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", - "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", + "version": "2.11.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", + "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3779,9 +3779,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", "dev": true, "funding": [ { @@ -3799,11 +3799,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" @@ -5186,9 +5186,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.402", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.402.tgz", - "integrity": "sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==", + "version": "1.5.403", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.403.tgz", + "integrity": "sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==", "dev": true, "license": "ISC" }, @@ -7954,9 +7954,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -11888,9 +11888,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", - "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { diff --git a/resources/lang/en_US/errors.php b/resources/lang/en_US/errors.php index 1590aba79d..8a38b40695 100644 --- a/resources/lang/en_US/errors.php +++ b/resources/lang/en_US/errors.php @@ -23,37 +23,37 @@ declare(strict_types=1); return [ - '404_header' => 'Firefly III cannot find this page.', - '404_page_does_not_exist' => 'The page you have requested does not exist. Please check that you have not entered the wrong URL. Did you make a typo perhaps?', - '404_send_error' => 'If you were redirected to this page automatically, please accept my apologies. There is a mention of this error in your log files and I would be grateful if you sent me the error to me.', - '404_github_link' => 'If you are sure this page should exist, please open a ticket on GitHub.', - 'whoops' => 'Whoops', - 'note_not_found_account' => 'Account ":name" has been deleted and can no longer be viewed. Please enjoy this overview of all other accounts of the same type.', - 'note_not_found_group' => 'Transaction ":description" has been deleted and can no longer be viewed. Please enjoy this overview of all other transactions of the same type.', + '404_header' => 'Firefly III cannot find this page.', + '404_page_does_not_exist' => 'The page you have requested does not exist. Please check that you have not entered the wrong URL. Did you make a typo perhaps?', + '404_send_error' => 'If you were redirected to this page automatically, please accept my apologies. There is a mention of this error in your log files and I would be grateful if you sent me the error to me.', + '404_github_link' => 'If you are sure this page should exist, please open a ticket on GitHub.', + 'whoops' => 'Whoops', + 'note_not_found_account' => 'Account ":name" has been deleted and can no longer be viewed. Please enjoy this overview of all other accounts of the same type.', + 'note_not_found_group' => 'Transaction ":description" has been deleted and can no longer be viewed. Please enjoy this overview of all other transactions of the same type.', 'note_not_found_reconciliation' => 'Reconciliation ":description" has been deleted and can no longer be viewed. Here is an overview of the account it belonged to.', - 'fatal_error' => 'There was a fatal error. Please check the log files in "storage/logs" or use "docker logs -f [container]" to see what\'s going on.', - 'maintenance_mode' => 'Firefly III is in maintenance mode.', - 'be_right_back' => 'Be right back!', - 'check_back' => 'Firefly III is down for some necessary maintenance. Please check back in a second. If you happen to see this message on the demo site, just wait a few minutes. The database is reset every few hours.', - 'error_occurred' => 'Whoops! An error occurred.', - 'db_error_occurred' => 'Whoops! A database error occurred.', - 'error_not_recoverable' => 'Unfortunately, this error was not recoverable :(. Firefly III broke. The error is:', - 'error' => 'Error', - 'error_location' => 'This error occurred in file :file on line :line with code :code.', - 'stacktrace' => 'Stack trace', - 'more_info' => 'More information', + 'fatal_error' => 'There was a fatal error. Please check the log files in "storage/logs" or use "docker logs -f [container]" to see what\'s going on.', + 'maintenance_mode' => 'Firefly III is in maintenance mode.', + 'be_right_back' => 'Be right back!', + 'check_back' => 'Firefly III is down for some necessary maintenance. Please check back in a second. If you happen to see this message on the demo site, just wait a few minutes. The database is reset every few hours.', + 'error_occurred' => 'Whoops! An error occurred.', + 'db_error_occurred' => 'Whoops! A database error occurred.', + 'error_not_recoverable' => 'Unfortunately, this error was not recoverable :(. Firefly III broke. The error is:', + 'error' => 'Error', + 'error_location' => 'This error occurred in file :file on line :line with code :code.', + 'stacktrace' => 'Stack trace', + 'more_info' => 'More information', - 'collect_info' => 'Please collect more information in the storage/logs directory where you will find log files. If you\'re running Docker, use docker logs -f [container].', - 'collect_info_more' => 'You can read more about collecting error information in the FAQ.', - 'github_help' => 'Get help on GitHub', - 'github_instructions' => 'You\'re more than welcome to open a new issue on GitHub.', - 'use_search' => 'Use the search!', - 'include_info' => 'Include the information from this debug page.', - 'tell_more' => 'Tell us more than "it says Whoops!"', - 'include_logs' => 'Include error logs (see above).', - 'what_did_you_do' => 'Tell us what you were doing.', - 'offline_header' => 'You are probably offline', - 'offline_unreachable' => 'Firefly III is unreachable. Your device is currently offline or the server is not working.', - 'offline_github' => 'If you are sure both your device and the server are online, please open a ticket on GitHub.', + 'collect_info' => 'Please collect more information in the storage/logs directory where you will find log files. If you\'re running Docker, use docker logs -f [container].', + 'collect_info_more' => 'You can read more about collecting error information in the FAQ.', + 'github_help' => 'Get help on GitHub', + 'github_instructions' => 'You\'re more than welcome to open a new issue on GitHub.', + 'use_search' => 'Use the search!', + 'include_info' => 'Include the information from this debug page.', + 'tell_more' => 'Tell us more than "it says Whoops!"', + 'include_logs' => 'Include error logs (see above).', + 'what_did_you_do' => 'Tell us what you were doing.', + 'offline_header' => 'You are probably offline', + 'offline_unreachable' => 'Firefly III is unreachable. Your device is currently offline or the server is not working.', + 'offline_github' => 'If you are sure both your device and the server are online, please open a ticket on GitHub.', ]; diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index 4ffd7f4355..f05a3dc6eb 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -23,8 +23,8 @@ declare(strict_types=1); return [ - 'no_auth_present' => 'Looks like you\'re not authenticated', - 'bad_url_parts' => 'The redirect URL is invalid.', + 'no_auth_present' => 'Looks like you\'re not authenticated', + 'bad_url_parts' => 'The redirect URL is invalid.', 'verifying_password' => 'Verifying password...', 'invalid_account_list' => 'Invalid account type list entry ":value"', 'invalid_transaction_type_list' => 'Invalid transaction type list',