diff --git a/framework/core/js/src/admin/components/StatusWidget.js b/framework/core/js/src/admin/components/StatusWidget.js index 34ef12579..91e045c46 100644 --- a/framework/core/js/src/admin/components/StatusWidget.js +++ b/framework/core/js/src/admin/components/StatusWidget.js @@ -5,6 +5,7 @@ import ItemList from '../../common/utils/ItemList'; import Dropdown from '../../common/components/Dropdown'; import Button from '../../common/components/Button'; import LoadingModal from './LoadingModal'; +import LinkButton from '../../common/components/LinkButton'; export default class StatusWidget extends DashboardWidget { className() { @@ -30,9 +31,26 @@ export default class StatusWidget extends DashboardWidget { ); - items.add('version-flarum', [Flarum,
, app.forum.attribute('version')]); - items.add('version-php', [PHP,
, app.data.phpVersion]); - items.add('version-mysql', [MySQL,
, app.data.mysqlVersion]); + items.add('version-flarum', [Flarum,
, app.forum.attribute('version')], 100); + items.add('version-php', [PHP,
, app.data.phpVersion], 90); + items.add('version-mysql', [MySQL,
, app.data.mysqlVersion], 80); + if (app.data.schedulerStatus) { + items.add( + 'schedule-status', + [ + + Scheduler{' '} + + , +
, + app.data.schedulerStatus, + ], + 70 + ); + } + + items.add('queue-driver', [Queue Driver,
, app.data.queueDriver], 60); + items.add('session-driver', [Session Driver,
, app.data.sessionDriver], 50); return items; } diff --git a/framework/core/locale/core.yml b/framework/core/locale/core.yml index c0e43a849..e21745c5a 100644 --- a/framework/core/locale/core.yml +++ b/framework/core/locale/core.yml @@ -56,6 +56,11 @@ core: clear_cache_button: Clear Cache description: Your forum at a glance. io_error_message: "Could not write to filesystem. Check your filesystem permissions and try again. Or try running from the command line." + status: + scheduler: + active: Active + inactive: Inactive + never-run: Never run title: Dashboard tools_button: Tools diff --git a/framework/core/src/Admin/Content/AdminPayload.php b/framework/core/src/Admin/Content/AdminPayload.php index ef570b0b7..4b45fc711 100644 --- a/framework/core/src/Admin/Content/AdminPayload.php +++ b/framework/core/src/Admin/Content/AdminPayload.php @@ -10,6 +10,7 @@ namespace Flarum\Admin\Content; use Flarum\Extension\ExtensionManager; +use Flarum\Foundation\ApplicationInfoProvider; use Flarum\Foundation\Config; use Flarum\Frontend\Document; use Flarum\Group\Permission; @@ -54,6 +55,11 @@ class AdminPayload */ protected $config; + /** + * @var ApplicationInfoProvider + */ + protected $appInfo; + /** * @param Container $container * @param SettingsRepositoryInterface $settings @@ -61,6 +67,7 @@ class AdminPayload * @param ConnectionInterface $db * @param Dispatcher $events * @param Config $config + * @param ApplicationInfoProvider $appInfo */ public function __construct( Container $container, @@ -68,7 +75,8 @@ class AdminPayload ExtensionManager $extensions, ConnectionInterface $db, Dispatcher $events, - Config $config + Config $config, + ApplicationInfoProvider $appInfo ) { $this->container = $container; $this->settings = $settings; @@ -76,6 +84,7 @@ class AdminPayload $this->db = $db; $this->events = $events; $this->config = $config; + $this->appInfo = $appInfo; } public function __invoke(Document $document, Request $request) @@ -95,10 +104,17 @@ class AdminPayload return array_keys($resourceDrivers); }, $this->container->make('flarum.http.slugDrivers')); - $document->payload['phpVersion'] = PHP_VERSION; - $document->payload['mysqlVersion'] = $this->db->selectOne('select version() as version')->version; + $document->payload['phpVersion'] = $this->appInfo->identifyPHPVersion(); + $document->payload['mysqlVersion'] = $this->appInfo->identifyDatabaseVersion(); $document->payload['debugEnabled'] = Arr::get($this->config, 'debug'); + if ($this->appInfo->scheduledTasksRegistered()) { + $document->payload['schedulerStatus'] = $this->appInfo->getSchedulerStatus(); + } + + $document->payload['queueDriver'] = $this->appInfo->identifyQueueDriver(); + $document->payload['sessionDriver'] = $this->appInfo->identifySessionDriver(); + /** * Used in the admin user list. Implemented as this as it matches the API in flarum/statistics. * If flarum/statistics ext is enabled, it will override this data with its own stats. diff --git a/framework/core/src/Console/ConsoleServiceProvider.php b/framework/core/src/Console/ConsoleServiceProvider.php index 439f85175..8252f78a0 100644 --- a/framework/core/src/Console/ConsoleServiceProvider.php +++ b/framework/core/src/Console/ConsoleServiceProvider.php @@ -16,12 +16,12 @@ use Flarum\Foundation\AbstractServiceProvider; use Flarum\Foundation\Console\AssetsPublishCommand; use Flarum\Foundation\Console\CacheClearCommand; use Flarum\Foundation\Console\InfoCommand; +use Flarum\Foundation\Console\ScheduleRunCommand; use Illuminate\Console\Scheduling\CacheEventMutex; use Illuminate\Console\Scheduling\CacheSchedulingMutex; use Illuminate\Console\Scheduling\EventMutex; use Illuminate\Console\Scheduling\Schedule as LaravelSchedule; use Illuminate\Console\Scheduling\ScheduleListCommand; -use Illuminate\Console\Scheduling\ScheduleRunCommand; use Illuminate\Console\Scheduling\SchedulingMutex; use Illuminate\Contracts\Container\Container; diff --git a/framework/core/src/Foundation/ApplicationInfoProvider.php b/framework/core/src/Foundation/ApplicationInfoProvider.php new file mode 100644 index 000000000..e032540ae --- /dev/null +++ b/framework/core/src/Foundation/ApplicationInfoProvider.php @@ -0,0 +1,212 @@ +settings = $settings; + $this->translator = $translator; + $this->schedule = $schedule; + $this->db = $db; + $this->config = $config; + $this->session = $session; + $this->sessionHandler = $sessionHandler; + $this->queue = $queue; + } + + /** + * Identify if any tasks are registered with the scheduler. + * + * @return bool + */ + public function scheduledTasksRegistered(): bool + { + return count($this->schedule->events()) > 0; + } + + /** + * Gets the current status of the scheduler. + * + * @return string + */ + public function getSchedulerStatus(): string + { + $status = $this->settings->get('schedule.last_run'); + + if (! $status) { + return $this->translator->trans('core.admin.dashboard.status.scheduler.never-run'); + } + + // If the schedule has not run in the last 5 minutes, mark it as inactive. + return Carbon::parse($status) > Carbon::now()->subMinutes(5) + ? $this->translator->trans('core.admin.dashboard.status.scheduler.active') + : $this->translator->trans('core.admin.status.scheduler.inactive'); + } + + /** + * Identify the queue driver in use. + * + * @return string + */ + public function identifyQueueDriver(): string + { + // Get class name + $queue = get_class($this->queue); + // Drop the namespace + $queue = Str::afterLast($queue, '\\'); + // Lowercase the class name + $queue = strtolower($queue); + // Drop everything like queue SyncQueue, RedisQueue + $queue = str_replace('queue', '', $queue); + + return $queue; + } + + /** + * Identify the version of the database we are connected to. + * + * @return string + */ + public function identifyDatabaseVersion(): string + { + return $this->db->selectOne('select version() as version')->version; + } + + /** + * Reports on the session driver in use based on three scenarios: + * 1. If the configured session driver is valid and in use, it will be returned. + * 2. If the configured session driver is invalid, fallback to the default one and mention it. + * 3. If the actual used driver (i.e `session.handler`) is different from the current one (configured or default), mention it. + */ + public function identifySessionDriver(): string + { + /* + * Get the configured driver and fallback to the default one. + */ + $defaultDriver = $this->session->getDefaultDriver(); + $configuredDriver = Arr::get($this->config, 'session.driver', $defaultDriver); + $driver = $configuredDriver; + + try { + // Try to get the configured driver instance. + // Driver instances are created on demand. + $this->session->driver($configuredDriver); + } catch (InvalidArgumentException $e) { + // An exception is thrown if the configured driver is not a valid driver. + // So we fallback to the default driver. + $driver = $defaultDriver; + } + + /* + * Get actual driver name from its class name. + * And compare that to the current configured driver. + */ + // Get class name + $handlerName = get_class($this->sessionHandler); + // Drop the namespace + $handlerName = Str::afterLast($handlerName, '\\'); + // Lowercase the class name + $handlerName = strtolower($handlerName); + // Drop everything like sessionhandler FileSessionHandler, DatabaseSessionHandler ..etc + $handlerName = str_replace('sessionhandler', '', $handlerName); + + if ($driver !== $handlerName) { + return "$handlerName (Code override. Configured to $configuredDriver)"; + } + + if ($driver !== $configuredDriver) { + return "$driver (Fallback default driver. Configured to invalid driver $configuredDriver)"; + } + + return $driver; + } + + /** + * Identifiy the current PHP version. + * + * @return string + */ + public function identifyPHPVersion(): string + { + return PHP_VERSION; + } +} diff --git a/framework/core/src/Foundation/Console/InfoCommand.php b/framework/core/src/Foundation/Console/InfoCommand.php index f7bd3e80b..34001b2e7 100644 --- a/framework/core/src/Foundation/Console/InfoCommand.php +++ b/framework/core/src/Foundation/Console/InfoCommand.php @@ -12,16 +12,10 @@ namespace Flarum\Foundation\Console; use Flarum\Console\AbstractCommand; use Flarum\Extension\ExtensionManager; use Flarum\Foundation\Application; +use Flarum\Foundation\ApplicationInfoProvider; use Flarum\Foundation\Config; use Flarum\Settings\SettingsRepositoryInterface; -use Flarum\User\SessionManager; -use Illuminate\Contracts\Queue\Queue; use Illuminate\Database\ConnectionInterface; -use Illuminate\Support\Arr; -use Illuminate\Support\Str; -use InvalidArgumentException; -use PDO; -use SessionHandlerInterface; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Helper\TableStyle; @@ -48,36 +42,22 @@ class InfoCommand extends AbstractCommand protected $db; /** - * @var Queue + * @var ApplicationInfoProvider */ - private $queue; - - /** - * @var SessionManager - */ - private $session; - - /** - * @var SessionHandlerInterface - */ - private $sessionHandler; + private $appInfo; public function __construct( ExtensionManager $extensions, Config $config, SettingsRepositoryInterface $settings, ConnectionInterface $db, - Queue $queue, - SessionManager $session, - SessionHandlerInterface $sessionHandler + ApplicationInfoProvider $appInfo ) { $this->extensions = $extensions; $this->config = $config; $this->settings = $settings; $this->db = $db; - $this->queue = $queue; - $this->session = $session; - $this->sessionHandler = $sessionHandler; + $this->appInfo = $appInfo; parent::__construct(); } @@ -98,10 +78,10 @@ class InfoCommand extends AbstractCommand protected function fire() { $coreVersion = $this->findPackageVersion(__DIR__.'/../../../', Application::VERSION); - $this->output->writeln("Flarum core $coreVersion"); + $this->output->writeln("Flarum core: $coreVersion"); - $this->output->writeln('PHP version: '.PHP_VERSION); - $this->output->writeln('MySQL version: '.$this->identifyDatabaseVersion()); + $this->output->writeln('PHP version: '.$this->appInfo->identifyPHPVersion()); + $this->output->writeln('MySQL version: '.$this->appInfo->identifyDatabaseVersion()); $phpExtensions = implode(', ', get_loaded_extensions()); $this->output->writeln("Loaded extensions: $phpExtensions"); @@ -110,8 +90,13 @@ class InfoCommand extends AbstractCommand $this->output->writeln('Base URL: '.$this->config->url()); $this->output->writeln('Installation path: '.getcwd()); - $this->output->writeln('Queue driver: '.$this->identifyQueueDriver()); - $this->output->writeln('Session driver: '.$this->identifySessionDriver()); + $this->output->writeln('Queue driver: '.$this->appInfo->identifyQueueDriver()); + $this->output->writeln('Session driver: '.$this->appInfo->identifySessionDriver()); + + if ($this->appInfo->scheduledTasksRegistered()) { + $this->output->writeln('Scheduler status: '.$this->appInfo->getSchedulerStatus()); + } + $this->output->writeln('Mail driver: '.$this->settings->get('mail_driver', 'unknown')); $this->output->writeln('Debug mode: '.($this->config->inDebugMode() ? 'ON' : 'off')); @@ -169,72 +154,4 @@ class InfoCommand extends AbstractCommand return $fallback; } - - private function identifyQueueDriver(): string - { - // Get class name - $queue = get_class($this->queue); - // Drop the namespace - $queue = Str::afterLast($queue, '\\'); - // Lowercase the class name - $queue = strtolower($queue); - // Drop everything like queue SyncQueue, RedisQueue - $queue = str_replace('queue', '', $queue); - - return $queue; - } - - private function identifyDatabaseVersion(): string - { - return $this->db->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); - } - - /** - * Reports on the session driver in use based on three scenarios: - * 1. If the configured session driver is valid and in use, it will be returned. - * 2. If the configured session driver is invalid, fallback to the default one and mention it. - * 3. If the actual used driver (i.e `session.handler`) is different from the current one (configured or default), mention it. - */ - private function identifySessionDriver(): string - { - /* - * Get the configured driver and fallback to the default one. - */ - $defaultDriver = $this->session->getDefaultDriver(); - $configuredDriver = Arr::get($this->config, 'session.driver', $defaultDriver); - $driver = $configuredDriver; - - try { - // Try to get the configured driver instance. - // Driver instances are created on demand. - $this->session->driver($configuredDriver); - } catch (InvalidArgumentException $e) { - // An exception is thrown if the configured driver is not a valid driver. - // So we fallback to the default driver. - $driver = $defaultDriver; - } - - /* - * Get actual driver name from its class name. - * And compare that to the current configured driver. - */ - // Get class name - $handlerName = get_class($this->sessionHandler); - // Drop the namespace - $handlerName = Str::afterLast($handlerName, '\\'); - // Lowercase the class name - $handlerName = strtolower($handlerName); - // Drop everything like sessionhandler FileSessionHandler, DatabaseSessionHandler ..etc - $handlerName = str_replace('sessionhandler', '', $handlerName); - - if ($driver !== $handlerName) { - return "$handlerName (Code override. Configured to $configuredDriver)"; - } - - if ($driver !== $configuredDriver) { - return "$driver (Fallback default driver. Configured to invalid driver $configuredDriver)"; - } - - return $driver; - } } diff --git a/framework/core/src/Foundation/Console/ScheduleRunCommand.php b/framework/core/src/Foundation/Console/ScheduleRunCommand.php new file mode 100644 index 000000000..45b2779d2 --- /dev/null +++ b/framework/core/src/Foundation/Console/ScheduleRunCommand.php @@ -0,0 +1,43 @@ +settings = $settings; + } + + /** + * {@inheritdoc} + */ + public function handle(Schedule $schedule, Dispatcher $dispatcher, ExceptionHandler $handler) + { + parent::handle($schedule, $dispatcher, $handler); + + $this->settings->set('schedule.last_run', $this->startedAt); + } +}