Final things.

This commit is contained in:
James Cole 2021-03-21 11:06:08 +01:00
parent 206845575c
commit 97a687e40a
No known key found for this signature in database
GPG Key ID: B5669F9493CDE38D
17 changed files with 305 additions and 67 deletions

View File

@ -0,0 +1,59 @@
<?php
/*
* CronController.php
* Copyright (c) 2021 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/>.
*/
namespace FireflyIII\Api\V1\Controllers\System;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\System\CronRequest;
use FireflyIII\Support\Http\Controllers\CronRunner;
use Illuminate\Http\JsonResponse;
use Log;
/**
* Class CronController
*/
class CronController extends Controller
{
use CronRunner;
/**
* @param CronRequest $request
* @param string $token
*
* @return JsonResponse
*/
public function cron(CronRequest $request, string $token): JsonResponse
{
$config = $request->getAll();
Log::debug(sprintf('Now in %s', __METHOD__));
$return = [];
$return['recurring_transactions'] = $this->runRecurring($config['force'], $config['date']);
$return['auto_budgets'] = $this->runAutoBudget($config['force'], $config['date']);
$return['telemetry'] = $this->runTelemetry($config['force'], $config['date']);
return response()->json($return);
}
}

View File

@ -0,0 +1,83 @@
<?php
/**
* ConfigurationRequest.php
* Copyright (c) 2019 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\Api\V1\Requests\System;
use Carbon\Carbon;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
/**
* Class CronRequest
*
* @codeCoverageIgnore
*/
class CronRequest extends FormRequest
{
use ConvertsDataTypes;
/**
* Verify the request.
*
* @return bool
*/
public function authorize(): bool
{
return true;
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
$data = [
'force' => false,
'date' => Carbon::now(),
];
if ($this->has('force')) {
$data['force'] = $this->boolean('force');
}
if ($this->has('date')) {
$data['date'] = $this->date('date');
}
return $data;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
return [
'force' => 'in:true,false',
'date' => 'date',
];
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\User;
use Log;
@ -74,6 +75,9 @@ class TransactionGroupFactory
if (null !== $title) {
$title = substr($title, 0, 1000);
}
if(0 === $collection->count()) {
throw new FireflyException('Created zero transaction journals.');
}
$group = new TransactionGroup;
$group->user()->associate($this->user);

View File

@ -22,26 +22,19 @@
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\System;
use FireflyIII\Support\Http\Controllers\CronRunner;
use Log;
/**
* Class CronController
*/
class CronController
{
use CronRunner;
/**
* @return string
*/
public function cron(): string
public function cron()
{
$results = [];
$results[] = $this->runRecurring();
$results[] = $this->runAutoBudget();
$results[] = $this->runTelemetry();
return implode("<br>\n", $results);
Log::error('The cron endpoint has moved to GET /api/v1/cron/[token]');
return response('The cron endpoint has moved to GET /api/v1/cron/[token]', 500);
}
}

View File

@ -133,16 +133,16 @@ class InstallController extends Controller
*/
public function keys(): void
{
// switch on PHP version.
// switch on PHP version.
if (7 === PHP_MAJOR_VERSION) {
$rsa = new \phpseclib\Crypt\RSA;
$keys = $rsa->createKey(4096);
}
if (8 === PHP_MAJOR_VERSION) {
$keys = \phpseclib3\Crypt\RSA::createKeys(4096);
$keys = \phpseclib3\Crypt\RSA::createKey(4096);
}
[$publicKey, $privateKey] = [
Passport::keyPath('oauth-public.key'),
Passport::keyPath('oauth-private.key'),

View File

@ -182,6 +182,9 @@ class Kernel extends HttpKernel
//'throttle:60,1',
'bindings',
],
'apiY' => [
'bindings',
],
];
/**
* The priority-sorted list of middleware.

View File

@ -110,7 +110,7 @@ class CreateRecurringTransactions implements ShouldQueue
// clear cache for user
app('preferences')->setForUser($recurrence->user, 'lastActivity', microtime());
Log::debug(sprintf('Now at recurrence #%d', $recurrence->id));
Log::debug(sprintf('Now at recurrence #%d of user #%d', $recurrence->id, $recurrence->user_id));
$createdReps = $this->handleRepetitions($recurrence);
Log::debug(sprintf('Done with recurrence #%d', $recurrence->id));
$result[$recurrence->user_id] = $result[$recurrence->user_id]->merge($createdReps);
@ -153,6 +153,7 @@ class CreateRecurringTransactions implements ShouldQueue
*/
private function validRecurrence(Recurrence $recurrence): bool
{
Log::debug(sprintf('Now filtering recurrence #%d, owned by user #%d', $recurrence->id, $recurrence->user_id));
// is not active.
if (!$this->active($recurrence)) {
Log::info(sprintf('Recurrence #%d is not active. Skipped.', $recurrence->id));
@ -203,6 +204,7 @@ class CreateRecurringTransactions implements ShouldQueue
return false;
}
Log::debug('Will be included.');
return true;
}

View File

@ -54,7 +54,7 @@ class RouteServiceProvider extends ServiceProvider
public function map(): void
{
$this->mapApiRoutes();
$this->mapCronApiRoutes();
$this->mapWebRoutes();
}
@ -71,6 +71,19 @@ class RouteServiceProvider extends ServiceProvider
->group(base_path('routes/api.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapCronApiRoutes(): void
{
Route::prefix('api/v1/cron')
->middleware('apiY')
->namespace($this->namespace)
->group(base_path('routes/api-noauth.php'));
}
/**
* Define the "web" routes for the application.
*

View File

@ -33,12 +33,15 @@ use Exception;
*/
abstract class AbstractCronjob
{
/** @var int */
public $timeBetweenRuns = 43200;
/** @var Carbon */
protected $date;
/** @var bool */
protected $force;
public int $timeBetweenRuns = 43200;
protected Carbon $date;
protected bool $force;
public bool $jobFired;
public bool $jobSucceeded;
public bool $jobErrored;
public ?string $message;
/**
* AbstractCronjob constructor.
@ -49,12 +52,16 @@ abstract class AbstractCronjob
{
$this->force = false;
$this->date = today(config('app.timezone'));
$this->jobErrored = false;
$this->jobSucceeded = false;
$this->jobFired = false;
$this->message = null;
}
/**
* @return bool
*
*/
abstract public function fire(): bool;
abstract public function fire(): void;
/**
* @param Carbon $date

View File

@ -39,7 +39,7 @@ class AutoBudgetCronjob extends AbstractCronjob
/**
* @inheritDoc
*/
public function fire(): bool
public function fire(): void
{
/** @var Configuration $config */
$config = app('fireflyconfig')->get('last_ab_job', 0);
@ -54,8 +54,8 @@ class AutoBudgetCronjob extends AbstractCronjob
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.');
return false;
$this->message = sprintf('It has been %s since the auto budget cron-job has fired. It will not fire now.', $diffForHumans);
return;
}
// fire job regardless.
@ -69,10 +69,7 @@ class AutoBudgetCronjob extends AbstractCronjob
}
$this->fireAutoBudget();
app('preferences')->mark();
return true;
}
/**
@ -85,6 +82,13 @@ class AutoBudgetCronjob extends AbstractCronjob
$job = app(CreateAutoBudgetLimits::class);
$job->setDate($this->date);
$job->handle();
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = false;
$this->jobSucceeded = true;
$this->message = 'Auto-budget cron job fired successfully.';
app('fireflyconfig')->set('last_ab_job', (int)$this->date->format('U'));
Log::info('Done with auto budget cron job task.');
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\Cronjobs;
use Carbon\Carbon;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Jobs\CreateRecurringTransactions;
use FireflyIII\Models\Configuration;
@ -35,16 +36,17 @@ use Log;
class RecurringCronjob extends AbstractCronjob
{
/**
* @return bool
* @throws FireflyException
*/
public function fire(): bool
public function fire(): void
{
Log::debug(sprintf('Now in %s', __METHOD__));
/** @var Configuration $config */
$config = app('fireflyconfig')->get('last_rt_job', 0);
$lastTime = (int)$config->data;
$diff = time() - $lastTime;
$diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), true);
if (0 === $lastTime) {
Log::info('Recurring transactions cron-job has never fired before.');
}
@ -53,8 +55,9 @@ class RecurringCronjob extends AbstractCronjob
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.');
$this->message = sprintf('It has been %s since the recurring transactions cron-job has fired. It will not fire now.', $diffForHumans);
return false;
return;
}
// fire job regardless.
@ -70,8 +73,6 @@ class RecurringCronjob extends AbstractCronjob
$this->fireRecurring();
app('preferences')->mark();
return true;
}
/**
@ -85,6 +86,13 @@ class RecurringCronjob extends AbstractCronjob
$job->setDate($this->date);
$job->setForce($this->force);
$job->handle();
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = false;
$this->jobSucceeded = true;
$this->message = 'Recurring transactions cron job fired successfully.';
app('fireflyconfig')->set('last_rt_job', (int)$this->date->format('U'));
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int)$this->date->format('U')));
Log::info('Done with recurring cron job task.');

View File

@ -40,13 +40,15 @@ class TelemetryCronjob extends AbstractCronjob
* @inheritDoc
* @throws FireflyException
*/
public function fire(): bool
public function fire(): void
{
// do not fire if telemetry is disabled.
if (false === config('firefly.send_telemetry') || false === config('firefly.feature_flags.telemetry')) {
Log::warning('Telemetry is disabled. The cron job will do nothing.');
$msg = 'Telemetry is disabled. The cron job will do nothing.';
$this->message = $msg;
Log::warning($msg);
return false;
return;
}
@ -63,8 +65,8 @@ class TelemetryCronjob extends AbstractCronjob
Log::info(sprintf('It has been %s since the telemetry cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The cron-job will not fire now.');
return false;
$this->message = sprintf('It has been %s since the telemetry cron-job has fired. It will not fire now.', $diffForHumans);
return;
}
// fire job regardless.
@ -80,8 +82,6 @@ class TelemetryCronjob extends AbstractCronjob
$this->fireTelemetry();
app('preferences')->mark();
return true;
}
@ -97,6 +97,11 @@ class TelemetryCronjob extends AbstractCronjob
$job->setForce($this->force);
$job->handle();
$this->jobFired = true;
$this->jobErrored = false;
$this->jobSucceeded = true;
$this->message = 'Telemetry cron job fired successfully.';
// TODO remove old, submitted telemetry data.
app('fireflyconfig')->set('last_tm_job', (int)$this->date->format('U'));

View File

@ -30,7 +30,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Laravel\Passport\Passport;
use Log;
use phpseclib3\Crypt\RSA;
/**
* Trait CreateStuff
@ -110,7 +110,7 @@ trait CreateStuff
$keys = $rsa->createKey(4096);
}
if (8 === PHP_MAJOR_VERSION) {
$keys = RSA::createKeys(4096);
$keys = \phpseclib3\Crypt\RSA::createKey(4096);
}
[$publicKey, $privateKey] = [

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
@ -34,60 +35,97 @@ use FireflyIII\Support\Cronjobs\TelemetryCronjob;
trait CronRunner
{
/**
* @return string
* @param bool $force
* @param Carbon $date
*
* @return array
*/
protected function runAutoBudget(): string
protected function runAutoBudget(bool $force, Carbon $date): array
{
/** @var AutoBudgetCronjob $autoBudget */
$autoBudget = app(AutoBudgetCronjob::class);
$autoBudget->setForce($force);
$autoBudget->setDate($date);
try {
$result = $autoBudget->fire();
$autoBudget->fire();
} catch (FireflyException $e) {
return $e->getMessage();
}
if (false === $result) {
return 'The auto budget cron job did not fire.';
return [
'job_fired' => false,
'job_succeeded' => false,
'job_errored' => true,
'message' => $e->getMessage(),
];
}
return 'The auto budget cron job fired successfully.';
return [
'job_fired' => $autoBudget->jobFired,
'job_succeeded' => $autoBudget->jobSucceeded,
'job_errored' => $autoBudget->jobErrored,
'message' => $autoBudget->message,
];
}
/**
* @return string
* @param bool $force
* @param Carbon $date
*
* @return array
*/
protected function runRecurring(): string
protected function runRecurring(bool $force, Carbon $date): array
{
/** @var RecurringCronjob $recurring */
$recurring = app(RecurringCronjob::class);
$recurring->setForce($force);
$recurring->setDate($date);
try {
$result = $recurring->fire();
$recurring->fire();
} catch (FireflyException $e) {
return $e->getMessage();
}
if (false === $result) {
return 'The recurring transaction cron job did not fire. It was fired less than half a day ago.';
return [
'job_fired' => false,
'job_succeeded' => false,
'job_errored' => true,
'message' => $e->getMessage(),
];
}
return 'The recurring transaction cron job fired successfully.';
return [
'job_fired' => $recurring->jobFired,
'job_succeeded' => $recurring->jobSucceeded,
'job_errored' => $recurring->jobErrored,
'message' => $recurring->message,
];
}
/**
* @return string
* @param bool $force
* @param Carbon $date
*
* @return array
*/
protected function runTelemetry(): string
protected function runTelemetry(bool $force, Carbon $date): array
{
/** @var TelemetryCronjob $telemetry */
$telemetry = app(TelemetryCronjob::class);
$telemetry->setForce($force);
$telemetry->setDate($date);
try {
$result = $telemetry->fire();
$telemetry->fire();
} catch (FireflyException $e) {
return $e->getMessage();
}
if (false === $result) {
return 'The telemetry cron job did not fire.';
return [
'job_fired' => false,
'job_succeeded' => false,
'job_errored' => true,
'message' => $e->getMessage(),
];
}
return 'The telemetry cron job fired successfully.';
return [
'job_fired' => $telemetry->jobFired,
'job_succeeded' => $telemetry->jobSucceeded,
'job_errored' => $telemetry->jobErrored,
'message' => $telemetry->message,
];
}
}

View File

@ -23,6 +23,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Changed
- OAuth settings are visible for LDAP users.
- If you set `FIREFLY_III_LAYOUT=v2`, Firefly III will show you the new layout on pages where it's available.
- New favicon.
- Cron job endpoint has changed.
### Deprecated
- The current layout will no longer receive fixes and changes.
@ -48,6 +50,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- [Issue 4235](https://github.com/firefly-iii/firefly-iii/issues/4235) Info popup instandard financial report does not apply report's account filter
- [Issue 4241](https://github.com/firefly-iii/firefly-iii/issues/4241) Broken chart
- PHP configs that have "MB" as size indicator would be parsed badly.
- RSA token generation is now PHP7/8 compatible.
### API
@ -61,6 +64,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- [Issue 4394](https://github.com/firefly-iii/firefly-iii/issues/4394) Storing budgets works again.
- [Issue 4426](https://github.com/firefly-iii/firefly-iii/issues/4426) Storing accounts would lead to bad capitalization in liability type.
- [Issue 4435](https://github.com/firefly-iii/firefly-iii/issues/4435) Storing piggy banks with object group information would fail.
- Users can submit almost any field without other fields changing as well.
## 5.4.6 (API 1.4.0) - 2020-10-07

13
routes/api-noauth.php Normal file
View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
// Cron job API routes:
Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\System', 'prefix' => '',
'as' => 'api.v1.cron.'],
static function () {
Route::get('{cliToken}', ['uses' => 'CronController@cron', 'as' => 'index']);
}
);

View File

@ -510,6 +510,8 @@ Route::group(
}
);
// Configuration API routes
Route::group(
['namespace' => 'FireflyIII\Api\V1\Controllers\System', 'prefix' => 'configuration',