Compare commits

...

6 Commits

Author SHA1 Message Date
github-actions[bot]
ff568653c8 Merge pull request #11940 from firefly-iii/release-1773385883
🤖 Automatically merge the PR into the develop branch.
2026-03-13 08:11:30 +01:00
JC5
21447a9b2f 🤖 Auto commit for release 'develop' on 2026-03-13 2026-03-13 08:11:23 +01:00
James Cole
238bfc819e Catch a null pointer. 2026-03-13 08:05:04 +01:00
James Cole
3fab4668fc Move copyright. 2026-03-13 04:14:46 +01:00
James Cole
190050d6cf Rate limit mail message. 2026-03-13 04:12:32 +01:00
James Cole
45d623e0c1 Fix some linting issues 2026-03-13 04:05:38 +01:00
30 changed files with 130 additions and 46 deletions

View File

@@ -1,10 +1,8 @@
<?php
declare(strict_types=1);
/*
* TriggerController.php
* Copyright (c) 2025 james@firefly-iii.org
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;

View File

@@ -98,7 +98,7 @@ final class TriggerController extends Controller
$enrichment->setUser($rule->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rules.test', [$rule->id]).$this->buildParams());
// resulting list is presented as JSON thing.

View File

@@ -105,7 +105,7 @@ final class TriggerController extends Controller
$enrichment->setUser($group->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rule-groups.test', [$group->id]).$this->buildParams());
// resulting list is presented as JSON thing.

View File

@@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
/*
* BatchController.php
* Copyright (c) 2026 james@firefly-iii.org
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\System;
use FireflyIII\Api\V1\Controllers\Controller;

View File

@@ -1,10 +1,8 @@
<?php
declare(strict_types=1);
/*
* AutocompleteApiRequest.php
* Copyright (c) 2025 james@firefly-iii.org
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Autocomplete;
use FireflyIII\Api\V1\Requests\AggregateFormRequest;

View File

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

View File

@@ -0,0 +1,79 @@
<?php
/*
* SendTestEmail.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Events\Test\OwnerTestsNotificationChannel;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Console\Command;
class SendTestEmail extends Command
{
use ShowsFriendlyMessages;
use VerifiesAccessToken;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:send-test-email
{--user=1 : The user ID.}
{--token= : The user\'s access token.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send test email';
/**
* Execute the console command.
*/
public function handle(): int
{
$user = $this->getUser();
if (!$user->hasRole('owner')) {
$this->friendlyError((string) trans('firefly.must_be_owner'));
return Command::FAILURE;
}
/** @var int $lastNotification */
$lastNotification = FireflyConfig::get('last_test_notification', 123)->data;
if ((time() - $lastNotification) < 120) {
$this->friendlyError((string) trans('firefly.test_rate_limited'));
return Command::FAILURE;
}
$owner = new OwnerNotifiable();
event(new OwnerTestsNotificationChannel('email', $owner));
FireflyConfig::set('last_test_notification', time());
return Command::SUCCESS;
}
}

View File

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

View File

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

View File

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

View File

@@ -33,7 +33,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

View File

@@ -31,7 +31,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Http\Controllers\CreateStuff;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\RedirectResponse;

View File

@@ -172,7 +172,7 @@ final class BudgetLimitController extends Controller
// return empty array:
return response()->json([]);
}
if ((int) $amount > 268435456) { // intentional cast to integer
if ((int) $amount > 268_435_456) { // intentional cast to integer
$amount = '268435456';
}
if (-1 === bccomp($amount, '0')) {
@@ -232,7 +232,7 @@ final class BudgetLimitController extends Controller
if ('' === $amount) {
$amount = '0';
}
if ((int) $amount > 268435456) { // 268 million, intentional integer
if ((int) $amount > 268_435_456) { // 268 million, intentional integer
$amount = '268435456';
}
// sanity check on amount:
@@ -254,8 +254,8 @@ final class BudgetLimitController extends Controller
$amount = bcmul($amount, '-1');
}
$notes = (string) $request->get('notes');
if (strlen($notes) > 32768) {
$notes = substr($notes, 0, 32768);
if (strlen($notes) > 32_768) {
$notes = substr($notes, 0, 32_768);
}
$limit = $this->blRepository->update($budgetLimit, ['amount' => $amount, 'notes' => $notes]);

View File

@@ -160,7 +160,7 @@ final class DebugController extends Controller
}
if ('' !== $logContent) {
// last few lines
$logContent = 'Truncated from this point <----|'.substr($logContent, -16384);
$logContent = 'Truncated from this point <----|'.substr($logContent, -16_384);
}
return view('debug', ['table' => $table, 'now' => $now, 'logContent' => $logContent]);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -79,7 +79,7 @@ return [
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2026-03-13',
'build_time' => 1773370359,
'build_time' => 1773385699,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

View File

@@ -197,6 +197,7 @@ return [
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
'journals_in_period_for_tag' => 'All transactions for tag :tag between :start and :end',
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
'test_rate_limited' => 'Please wait a moment before trying again',
'exchange_rate_instructions' => 'Asset account "@name" only accepts transactions in @primary_currency. If you wish to use @foreign_currency instead, make sure that the amount in @primary_currency is known as well:',
'transfer_exchange_rate_instructions' => 'Source asset account "@source_name" only accepts transactions in @source_currency. Destination asset account "@dest_name" only accepts transactions in @dest_currency. You must provide the transferred amount correctly in both currencies.',
'transaction_data' => 'Transaction data',
@@ -1526,6 +1527,7 @@ return [
'administration_role_mng_currencies' => 'Manage currencies',
'administration_role_view_reports' => 'View reports',
'administration_role_full' => 'Full access',
'must_be_owner' => 'You must be system owner to do this',
// mfa
'enable_mfa' => 'Enable multi-factor authentication',