From cb2c52cddb025002910e65f19e7fe95b12d2b588 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 12 Aug 2018 14:26:11 +0200 Subject: [PATCH] New cronjob code. --- app/Console/Commands/Cron.php | 65 ++++++++++++++ app/Console/Kernel.php | 14 +++- .../Controllers/System/CronController.php | 65 ++++++++++++++ app/Http/Kernel.php | 10 ++- app/Support/Binder/CLIToken.php | 62 ++++++++++++++ app/Support/Cronjobs/AbstractCronjob.php | 39 +++++++++ app/Support/Cronjobs/RecurringCronjob.php | 84 +++++++++++++++++++ config/firefly.php | 1 + routes/web.php | 6 ++ 9 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 app/Console/Commands/Cron.php create mode 100644 app/Http/Controllers/System/CronController.php create mode 100644 app/Support/Binder/CLIToken.php create mode 100644 app/Support/Cronjobs/AbstractCronjob.php create mode 100644 app/Support/Cronjobs/RecurringCronjob.php diff --git a/app/Console/Commands/Cron.php b/app/Console/Commands/Cron.php new file mode 100644 index 0000000000..4678382102 --- /dev/null +++ b/app/Console/Commands/Cron.php @@ -0,0 +1,65 @@ +fire(); + } catch (FireflyException $e) { + $this->error($e->getMessage()); + + return 0; + } + if (false === $result) { + $this->line('The recurring transaction cron job did not fire.'); + } + if (true === $result) { + $this->line('The recurring transaction cron job fired successfully.'); + } + + $this->info('More feedback on the cron jobs can be found in the log files.'); + + return 0; + } + + +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 3c1fe481de..1e4f9eb172 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -52,6 +52,18 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule): void { - $schedule->job(new CreateRecurringTransactions(new Carbon))->daily(); + $schedule->call(function() { + echo "\n"; + echo '------------'; + echo "\n"; + echo wordwrap('Firefly III no longer users the Laravel scheduler to do cron jobs! Please read the instructions here:'); + echo "\n"; + echo 'https://firefly-iii.readthedocs.io/en/latest/'; + echo "\n\n"; + echo 'Disable this cron job!'; + echo "\n"; + echo '------------'; + echo "\n"; + })->everyMinute(); } } diff --git a/app/Http/Controllers/System/CronController.php b/app/Http/Controllers/System/CronController.php new file mode 100644 index 0000000000..46a50c8384 --- /dev/null +++ b/app/Http/Controllers/System/CronController.php @@ -0,0 +1,65 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\System; + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Support\Cronjobs\RecurringCronjob; + +/** + * Class CronController + */ +class CronController +{ + /** + * @param string $token + * + * @return string + */ + public function cron(string $token): string + { + $results = []; + $results[] = $this->runRecurring(); + + return implode("
\n", $results); + } + + /** + * @return string + */ + private function runRecurring(): string + { + $recurring = new RecurringCronjob; + try { + $result = $recurring->fire(); + } catch (FireflyException $e) { + return $e->getMessage(); + } + if (false === $result) { + return 'The recurring transaction cron job did not fire.'; + } + + return 'The recurring transaction cron job fired successfully.'; + } + +} \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index b21c6bf743..514b660f1d 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -80,7 +80,7 @@ class Kernel extends HttpKernel // does not check login // does not check 2fa // does not check activation - 'web' => [ + 'web' => [ Sandstorm::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, @@ -90,6 +90,14 @@ class Kernel extends HttpKernel CreateFreshApiToken::class, ], + // only the basic variable binders. + 'binders-only' => [ + Installer::class, + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + Binder::class, + ], + // MUST NOT be logged in. Does not care about 2FA or confirmation. 'user-not-logged-in' => [ Installer::class, diff --git a/app/Support/Binder/CLIToken.php b/app/Support/Binder/CLIToken.php new file mode 100644 index 0000000000..faeb5aef34 --- /dev/null +++ b/app/Support/Binder/CLIToken.php @@ -0,0 +1,62 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Binder; + +use FireflyIII\Repositories\User\UserRepositoryInterface; +use Illuminate\Routing\Route; +use Illuminate\Support\Collection; +use Log; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + +/** + * Class CLIToken + */ +class CLIToken implements BinderInterface +{ + + /** + * @param string $value + * @param Route $route + * + * @return mixed + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public static function routeBinder(string $value, Route $route) + { + /** @var UserRepositoryInterface $repository */ + $repository = app(UserRepositoryInterface::class); + /** @var Collection $users */ + $users = $repository->all(); + + foreach ($users as $user) { + $accessToken = app('preferences')->getForUser($user, 'access_token', null); + if ($accessToken->data === $value) { + Log::info(sprintf('Recognized user #%d (%s) from his acccess token.', $user->id, $user->email)); + + return $value; + } + } + throw new NotFoundHttpException; + } +} \ No newline at end of file diff --git a/app/Support/Cronjobs/AbstractCronjob.php b/app/Support/Cronjobs/AbstractCronjob.php new file mode 100644 index 0000000000..3eebb176be --- /dev/null +++ b/app/Support/Cronjobs/AbstractCronjob.php @@ -0,0 +1,39 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Cronjobs; + +/** + * Class AbstractCronjob + */ +abstract class AbstractCronjob +{ + /** @var int */ + public $timeBetweenRuns = 43200; + + /** + * @return bool + */ + abstract public function fire(): bool; + +} \ No newline at end of file diff --git a/app/Support/Cronjobs/RecurringCronjob.php b/app/Support/Cronjobs/RecurringCronjob.php new file mode 100644 index 0000000000..c75e11ad29 --- /dev/null +++ b/app/Support/Cronjobs/RecurringCronjob.php @@ -0,0 +1,84 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Cronjobs; + +use Carbon\Carbon; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Jobs\CreateRecurringTransactions; +use FireflyIII\Models\Configuration; +use Log; + +/** + * Class RecurringCronjob + */ +class RecurringCronjob extends AbstractCronjob +{ + + /** + * @return bool + * @throws FireflyException + */ + public function fire(): bool + { + /** @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 cronjob has never fired before.'); + } + // less than half a day ago: + if ($lastTime > 0 && $diff <= 43200) { + Log::info(sprintf('It has been %s since the recurring transactions cronjob has fired. It will not fire now.', $diffForHumans)); + + return false; + } + + if ($lastTime > 0 && $diff > 43200) { + Log::info(sprintf('It has been %s since the recurring transactions cronjob has fired. It will fire now!', $diffForHumans)); + } + + try { + $this->fireRecurring(); + } catch (FireflyException $e) { + Log::error($e->getMessage()); + Log::error($e->getTraceAsString()); + throw new FireflyException(sprintf('Could not run recurring transaction cron job: %s', $e->getMessage())); + } + + return true; + } + + /** + * + * @throws FireflyException + */ + private function fireRecurring(): void + { + $job = new CreateRecurringTransactions(new Carbon); + $job->handle(); + app('fireflyconfig')->set('last_rt_job', time()); + } +} \ No newline at end of file diff --git a/config/firefly.php b/config/firefly.php index 69f9fd000c..99afb8c215 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -307,6 +307,7 @@ return [ 'fromCurrencyCode' => \FireflyIII\Support\Binder\CurrencyCode::class, 'toCurrencyCode' => \FireflyIII\Support\Binder\CurrencyCode::class, 'unfinishedJournal' => \FireflyIII\Support\Binder\UnfinishedJournal::class, + 'cliToken' => \FireflyIII\Support\Binder\CLIToken::class, ], diff --git a/routes/web.php b/routes/web.php index 88246c4aaa..a492dec37a 100755 --- a/routes/web.php +++ b/routes/web.php @@ -33,6 +33,12 @@ Route::group( } ); +Route::group( + ['middleware' => 'binders-only','namespace' => 'FireflyIII\Http\Controllers\System', 'as' => 'cron.', 'prefix' => 'cron'], function () { + Route::get('run/{cliToken}', ['uses' => 'CronController@cron', 'as' => 'cron']); +} +); + /** * These routes only work when the user is NOT logged in. */