Add cron routine for update.

This commit is contained in:
James Cole 2025-02-15 06:12:02 +01:00
parent fc9429bf3e
commit 8457a1c881
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
5 changed files with 163 additions and 41 deletions

View File

@ -26,11 +26,13 @@ namespace FireflyIII\Console\Commands\Tools;
use Carbon\Carbon;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\BillWarningCronjob;
use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use FireflyIII\Support\Cronjobs\UpdateCheckCronjob;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
@ -43,6 +45,7 @@ class Cron extends Command
protected $signature = 'firefly-iii:cron
{--F|force : Force the cron job(s) to execute.}
{--date= : Set the date in YYYY-MM-DD to make Firefly III think that\'s the current date.}
{--check-version : Check if there is a new Firefly III version. Other tasks will be skipped unless also requested.}
{--download-cer : Download exchange rates. Other tasks will be skipped unless also requested.}
{--create-recurring : Create recurring transactions. Other tasks will be skipped unless also requested.}
{--create-auto-budgets : Create auto budgets. Other tasks will be skipped unless also requested.}
@ -51,7 +54,11 @@ class Cron extends Command
public function handle(): int
{
$doAll = !$this->option('download-cer') && !$this->option('create-recurring') && !$this->option('create-auto-budgets') && !$this->option('send-bill-warnings');
$doAll = !$this->option('download-cer') &&
!$this->option('create-recurring') &&
!$this->option('create-auto-budgets') &&
!$this->option('send-bill-warnings') &&
!$this->option('check-version');
$date = null;
try {
@ -72,6 +79,17 @@ class Cron extends Command
}
}
// check for new version
if ($doAll || $this->option('check-version')) {
try {
$this->checkForUpdates($force);
} catch (FireflyException $e) {
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
$this->friendlyError($e->getMessage());
}
}
// Fire recurring transaction cron job.
if ($doAll || $this->option('create-recurring')) {
try {
@ -204,4 +222,20 @@ class Cron extends Command
$this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
}
}
private function checkForUpdates(bool $force): void {
$updateCheck = new UpdateCheckCronjob();
$updateCheck->setForce($force);
$updateCheck->fire();
if ($updateCheck->jobErrored) {
$this->friendlyError(sprintf('Error in "update check" cron: %s', $updateCheck->message));
}
if ($updateCheck->jobFired) {
$this->friendlyInfo(sprintf('"Update check" cron fired: %s', $updateCheck->message));
}
if ($updateCheck->jobSucceeded) {
$this->friendlyPositive(sprintf('"Update check" cron ran with success: %s', $updateCheck->message));
}
}
}

View File

@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Update\UpdateTrait;
use FireflyIII\Models\Configuration;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Support\Facades\Log;
/**
* Class VersionCheckEventHandler
@ -45,13 +46,13 @@ class VersionCheckEventHandler
*/
public function checkForUpdates(RequestedVersionCheckStatus $event): void
{
app('log')->debug('Now in checkForUpdates()');
Log::debug('Now in checkForUpdates()');
// should not check for updates:
$permission = app('fireflyconfig')->get('permission_update_check', -1);
$value = (int) $permission->data;
if (1 !== $value) {
app('log')->debug('Update check is not enabled.');
Log::debug('Update check is not enabled.');
$this->warnToCheckForUpdates($event);
return;
@ -61,7 +62,7 @@ class VersionCheckEventHandler
$repository = app(UserRepositoryInterface::class);
$user = $event->user;
if (!$repository->hasRole($user, 'owner')) {
app('log')->debug('User is not admin, done.');
Log::debug('User is not admin, done.');
return;
}
@ -70,14 +71,14 @@ class VersionCheckEventHandler
$lastCheckTime = app('fireflyconfig')->get('last_update_check', time());
$now = time();
$diff = $now - $lastCheckTime->data;
app('log')->debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800) {
app('log')->debug(sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
Log::debug(sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
return;
}
// last check time was more than a week ago.
app('log')->debug('Have not checked for a new version in a week!');
Log::debug('Have not checked for a new version in a week!');
$release = $this->getLatestRelease();
session()->flash($release['level'], $release['message']);
@ -93,7 +94,7 @@ class VersionCheckEventHandler
$repository = app(UserRepositoryInterface::class);
$user = $event->user;
if (!$repository->hasRole($user, 'owner')) {
app('log')->debug('User is not admin, done.');
Log::debug('User is not admin, done.');
return;
}
@ -102,14 +103,14 @@ class VersionCheckEventHandler
$lastCheckTime = app('fireflyconfig')->get('last_update_warning', time());
$now = time();
$diff = $now - $lastCheckTime->data;
app('log')->debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
Log::debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800 * 4) {
app('log')->debug(sprintf('Warned about updates less than four weeks ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
Log::debug(sprintf('Warned about updates less than four weeks ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
return;
}
// last check time was more than a week ago.
app('log')->debug('Have warned about a new version in four weeks!');
Log::debug('Have warned about a new version in four weeks!');
session()->flash('info', (string) trans('firefly.disabled_but_check'));
app('fireflyconfig')->set('last_update_warning', time());

View File

@ -37,7 +37,7 @@ class UpdateRequest implements UpdateRequestInterface
{
public function getUpdateInformation(string $channel): array
{
app('log')->debug(sprintf('Now in getUpdateInformation(%s)', $channel));
Log::debug(sprintf('Now in getUpdateInformation(%s)', $channel));
$information = [
'level' => 'error',
'message' => (string) trans('firefly.unknown_error'),
@ -46,8 +46,8 @@ class UpdateRequest implements UpdateRequestInterface
// try to get array from update server:
$updateInfo = $this->contactServer($channel);
if ('error' === $updateInfo['level']) {
app('log')->error('Update information contains an error.');
app('log')->error($updateInfo['message']);
Log::error('Update information contains an error.');
Log::error($updateInfo['message']);
$information['message'] = $updateInfo['message'];
return $information;
@ -59,7 +59,7 @@ class UpdateRequest implements UpdateRequestInterface
private function contactServer(string $channel): array
{
app('log')->debug(sprintf('Now in contactServer(%s)', $channel));
Log::debug(sprintf('Now in contactServer(%s)', $channel));
// always fall back to current version:
$return = [
'version' => config('firefly.version'),
@ -69,7 +69,7 @@ class UpdateRequest implements UpdateRequestInterface
];
$url = config('firefly.update_endpoint');
app('log')->debug(sprintf('Going to call %s', $url));
Log::debug(sprintf('Going to call %s', $url));
try {
$client = new Client();
@ -81,17 +81,17 @@ class UpdateRequest implements UpdateRequestInterface
];
$res = $client->request('GET', $url, $options);
} catch (GuzzleException $e) {
app('log')->error('Ran into Guzzle error.');
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
Log::error('Ran into Guzzle error.');
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$return['message'] = sprintf('Guzzle: %s', strip_tags($e->getMessage()));
return $return;
}
if (200 !== $res->getStatusCode()) {
app('log')->error(sprintf('Response status from server is %d.', $res->getStatusCode()));
app('log')->error((string) $res->getBody());
Log::error(sprintf('Response status from server is %d.', $res->getStatusCode()));
Log::error((string) $res->getBody());
$return['message'] = sprintf('Error: %d', $res->getStatusCode());
return $return;
@ -101,16 +101,16 @@ class UpdateRequest implements UpdateRequestInterface
try {
$json = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
app('log')->error('Body is not valid JSON');
app('log')->error($body);
Log::error('Body is not valid JSON');
Log::error($body);
$return['message'] = 'Invalid JSON :(';
return $return;
}
if (!array_key_exists($channel, $json['firefly_iii'])) {
app('log')->error(sprintf('No valid update channel "%s"', $channel));
app('log')->error($body);
Log::error(sprintf('No valid update channel "%s"', $channel));
Log::error($body);
$return['message'] = sprintf('Unknown update channel "%s" :(', $channel);
}
@ -124,7 +124,7 @@ class UpdateRequest implements UpdateRequestInterface
$return['level'] = 'success';
$return['date'] = $date->startOfDay();
app('log')->info('Response from update server', $response);
Log::info('Response from update server', $response);
return $return;
}
@ -134,7 +134,7 @@ class UpdateRequest implements UpdateRequestInterface
*/
private function parseResult(array $information): array
{
app('log')->debug('Now in parseResult()', $information);
Log::debug('Now in parseResult()', $information);
$current = (string) config('firefly.version');
$latest = (string) $information['version'];
@ -148,7 +148,7 @@ class UpdateRequest implements UpdateRequestInterface
$compare = version_compare($latest, $current);
app('log')->debug(sprintf('Current version is "%s", latest is "%s", result is: %d', $current, $latest, $compare));
Log::debug(sprintf('Current version is "%s", latest is "%s", result is: %d', $current, $latest, $compare));
// -1: you're running a newer version:
if (-1 === $compare) {
@ -206,7 +206,7 @@ class UpdateRequest implements UpdateRequestInterface
'level' => 'info',
'message' => (string) trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $latest]),
];
app('log')->debug('User is running a newer version', $return);
Log::debug('User is running a newer version', $return);
return $return;
}
@ -217,14 +217,14 @@ class UpdateRequest implements UpdateRequestInterface
'level' => 'info',
'message' => (string) trans('firefly.update_current_version_alert', ['version' => $current]),
];
app('log')->debug('User is the current version.', $return);
Log::debug('User is the current version.', $return);
return $return;
}
private function releasedNewAlpha(string $current, string $latest, Carbon $date): array
{
app('log')->debug('New release is also a alpha!');
Log::debug('New release is also a alpha!');
$message = (string) trans(
'firefly.update_new_version_alert',
[
@ -242,7 +242,7 @@ class UpdateRequest implements UpdateRequestInterface
private function releasedNewBeta(string $current, string $latest, Carbon $date): array
{
app('log')->debug('New release is also a beta!');
Log::debug('New release is also a beta!');
$message = (string) trans(
'firefly.update_new_version_alert',
[
@ -260,7 +260,7 @@ class UpdateRequest implements UpdateRequestInterface
private function releasedNewVersion(string $current, string $latest, Carbon $date): array
{
app('log')->debug('New release is old enough.');
Log::debug('New release is old enough.');
$message = (string) trans(
'firefly.update_new_version_alert',
[
@ -269,7 +269,7 @@ class UpdateRequest implements UpdateRequestInterface
'date' => $date->isoFormat((string) trans('config.month_and_day_js')),
]
);
app('log')->debug('New release is here!', [$message]);
Log::debug('New release is here!', [$message]);
event(new NewVersionAvailable($message));
return [

View File

@ -27,6 +27,7 @@ namespace FireflyIII\Support\Cronjobs;
use Carbon\Carbon;
use FireflyIII\Jobs\DownloadExchangeRates;
use FireflyIII\Models\Configuration;
use Illuminate\Support\Facades\Log;
/**
* Class ExchangeRatesCronjob
@ -41,23 +42,23 @@ class ExchangeRatesCronjob extends AbstractCronjob
$diff = time() - $lastTime;
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
if (0 === $lastTime) {
app('log')->info('Exchange rates cron-job has never fired before.');
Log::info('Exchange rates cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
app('log')->info(sprintf('It has been %s since the exchange rates cron-job has fired.', $diffForHumans));
Log::info(sprintf('It has been %s since the exchange rates cron-job has fired.', $diffForHumans));
if (false === $this->force) {
app('log')->info('The exchange rates cron-job will not fire now.');
Log::info('The exchange rates cron-job will not fire now.');
$this->message = sprintf('It has been %s since the exchange rates cron-job has fired. It will not fire now.', $diffForHumans);
return;
}
app('log')->info('Execution of the exchange rates cron-job has been FORCED.');
Log::info('Execution of the exchange rates cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
app('log')->info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans));
Log::info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans));
}
$this->fireExchangeRateJob();
@ -66,7 +67,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
private function fireExchangeRateJob(): void
{
app('log')->info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d')));
Log::info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d')));
/** @var DownloadExchangeRates $job */
$job = app(DownloadExchangeRates::class);
@ -80,6 +81,6 @@ class ExchangeRatesCronjob extends AbstractCronjob
$this->message = 'Exchange rates cron job fired successfully.';
app('fireflyconfig')->set('last_cer_job', (int) $this->date->format('U'));
app('log')->info('Done with exchange rates job task.');
Log::info('Done with exchange rates job task.');
}
}

View File

@ -0,0 +1,86 @@
<?php
/*
* UpdateCheckCronjob.php
* Copyright (c) 2025 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\Support\Cronjobs;
use FireflyIII\Helpers\Update\UpdateTrait;
use FireflyIII\Models\Configuration;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
class UpdateCheckCronjob extends AbstractCronjob
{
use UpdateTrait;
#[\Override] public function fire(): void
{
Log::debug('Now in checkForUpdates()');
// should not check for updates:
$permission = app('fireflyconfig')->get('permission_update_check', -1);
$value = (int) $permission->data;
if (1 !== $value) {
Log::debug('Update check is not enabled.');
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = 'The update check is not enabled.';
return;
}
// TODO this is duplicate.
/** @var Configuration $lastCheckTime */
$lastCheckTime = FireflyConfig::get('last_update_check', time());
$now = time();
$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) {
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data));
return;
}
// last check time was more than a week ago.
Log::debug('Have not checked for a new version in a week!');
$release = $this->getLatestRelease();
if('error' === $release['level']) {
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = $release['message'];
return;
}
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = false;
$this->jobSucceeded = false;
$this->message = $release['message'];
}
}