Implement the system status api endpoint. Closes #1936
This commit is contained in:
@@ -11,13 +11,38 @@
|
|||||||
|
|
||||||
namespace CachetHQ\Cachet\Composers;
|
namespace CachetHQ\Cachet\Composers;
|
||||||
|
|
||||||
|
use CachetHQ\Cachet\Integrations\Core\System;
|
||||||
use CachetHQ\Cachet\Models\Component;
|
use CachetHQ\Cachet\Models\Component;
|
||||||
use CachetHQ\Cachet\Models\ComponentGroup;
|
use CachetHQ\Cachet\Models\ComponentGroup;
|
||||||
use CachetHQ\Cachet\Models\Incident;
|
use CachetHQ\Cachet\Models\Incident;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the status page composer.
|
||||||
|
*
|
||||||
|
* @author James Brooks <james@alt-three.com>
|
||||||
|
*/
|
||||||
class StatusPageComposer
|
class StatusPageComposer
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The system instance.
|
||||||
|
*
|
||||||
|
* @var \CachetHQ\Cachet\Integrations\Contracts\System
|
||||||
|
*/
|
||||||
|
protected $system;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new status page composer instance.
|
||||||
|
*
|
||||||
|
* @param \CachetHQ\Cachet\Integrations\Contracts\System $system
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(System $system)
|
||||||
|
{
|
||||||
|
$this->system = $system;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index page view composer.
|
* Index page view composer.
|
||||||
*
|
*
|
||||||
@@ -27,42 +52,7 @@ class StatusPageComposer
|
|||||||
*/
|
*/
|
||||||
public function compose(View $view)
|
public function compose(View $view)
|
||||||
{
|
{
|
||||||
$totalComponents = Component::enabled()->count();
|
$status = $this->system->getStatus();
|
||||||
$majorOutages = Component::enabled()->status(4)->count();
|
|
||||||
$isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false;
|
|
||||||
|
|
||||||
// Default data
|
|
||||||
$withData = [
|
|
||||||
'system_status' => 'info',
|
|
||||||
'system_message' => trans_choice('cachet.service.bad', $totalComponents),
|
|
||||||
'favicon' => 'favicon-high-alert',
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($isMajorOutage) {
|
|
||||||
$withData = [
|
|
||||||
'system_status' => 'danger',
|
|
||||||
'system_message' => trans_choice('cachet.service.major', $totalComponents),
|
|
||||||
'favicon' => 'favicon-high-alert',
|
|
||||||
];
|
|
||||||
} elseif (Component::enabled()->notStatus(1)->count() === 0) {
|
|
||||||
// If all our components are ok, do we have any non-fixed incidents?
|
|
||||||
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) {
|
|
||||||
return $incident->status > 0;
|
|
||||||
});
|
|
||||||
$incidentCount = $incidents->count();
|
|
||||||
|
|
||||||
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
|
|
||||||
$withData = [
|
|
||||||
'system_status' => 'success',
|
|
||||||
'system_message' => trans_choice('cachet.service.good', $totalComponents),
|
|
||||||
'favicon' => 'favicon',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (Component::enabled()->whereIn('status', [2, 3])->count() > 0) {
|
|
||||||
$withData['favicon'] = 'favicon-medium-alert';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scheduled maintenance code.
|
// Scheduled maintenance code.
|
||||||
$scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get();
|
$scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get();
|
||||||
@@ -72,7 +62,7 @@ class StatusPageComposer
|
|||||||
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
|
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
|
||||||
$ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
|
$ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
|
||||||
|
|
||||||
$view->with($withData)
|
$view->with($status)
|
||||||
->withComponentGroups($componentGroups)
|
->withComponentGroups($componentGroups)
|
||||||
->withUngroupedComponents($ungroupedComponents)
|
->withUngroupedComponents($ungroupedComponents)
|
||||||
->withScheduledMaintenance($scheduledMaintenance);
|
->withScheduledMaintenance($scheduledMaintenance);
|
||||||
|
|||||||
47
app/Foundation/Providers/IntegrationServiceProvider.php
Normal file
47
app/Foundation/Providers/IntegrationServiceProvider.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Cachet.
|
||||||
|
*
|
||||||
|
* (c) Alt Three Services Limited
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace CachetHQ\Cachet\Foundation\Providers;
|
||||||
|
|
||||||
|
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
|
||||||
|
use CachetHQ\Cachet\Integrations\Core\System;
|
||||||
|
use Illuminate\Contracts\Container\Container;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the integration service provider.
|
||||||
|
*
|
||||||
|
* @author James Brooks <james@alt-three.com>
|
||||||
|
*/
|
||||||
|
class IntegrationServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register the service provider.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
$this->registerSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the system class.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function registerSystem()
|
||||||
|
{
|
||||||
|
$this->app->singleton(SystemContract::class, function (Container $app) {
|
||||||
|
return new System();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace CachetHQ\Cachet\Http\Controllers\Api;
|
namespace CachetHQ\Cachet\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use CachetHQ\Cachet\Integrations\Contracts\System;
|
||||||
use CachetHQ\Cachet\Integrations\Releases;
|
use CachetHQ\Cachet\Integrations\Releases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,4 +45,16 @@ class GeneralController extends AbstractApiController
|
|||||||
'latest' => $latest,
|
'latest' => $latest,
|
||||||
])->item(CACHET_VERSION);
|
])->item(CACHET_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the system status message.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function status()
|
||||||
|
{
|
||||||
|
$system = app()->make(System::class)->getStatus();
|
||||||
|
|
||||||
|
return $this->item($system['system_message']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class ApiRoutes
|
|||||||
$router->group(['middleware' => ['auth.api']], function (Registrar $router) {
|
$router->group(['middleware' => ['auth.api']], function (Registrar $router) {
|
||||||
$router->get('ping', 'GeneralController@ping');
|
$router->get('ping', 'GeneralController@ping');
|
||||||
$router->get('version', 'GeneralController@version');
|
$router->get('version', 'GeneralController@version');
|
||||||
|
$router->get('status', 'GeneralController@status');
|
||||||
|
|
||||||
$router->get('components', 'ComponentController@getComponents');
|
$router->get('components', 'ComponentController@getComponents');
|
||||||
$router->get('components/groups', 'ComponentGroupController@getGroups');
|
$router->get('components/groups', 'ComponentGroupController@getGroups');
|
||||||
|
|||||||
27
app/Integrations/Contracts/System.php
Normal file
27
app/Integrations/Contracts/System.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Cachet.
|
||||||
|
*
|
||||||
|
* (c) Alt Three Services Limited
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace CachetHQ\Cachet\Integrations\Contracts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the system interface.
|
||||||
|
*
|
||||||
|
* @author James Brooks <james@alt-three.com>
|
||||||
|
*/
|
||||||
|
interface System
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the entire system status.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getStatus();
|
||||||
|
}
|
||||||
70
app/Integrations/Core/System.php
Normal file
70
app/Integrations/Core/System.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Cachet.
|
||||||
|
*
|
||||||
|
* (c) Alt Three Services Limited
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace CachetHQ\Cachet\Integrations\Core;
|
||||||
|
|
||||||
|
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
|
||||||
|
use CachetHQ\Cachet\Models\Component;
|
||||||
|
use CachetHQ\Cachet\Models\Incident;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the core system class.
|
||||||
|
*
|
||||||
|
* @author James Brooks <james@alt-three.com>
|
||||||
|
*/
|
||||||
|
class System implements SystemContract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the entire system status.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getStatus()
|
||||||
|
{
|
||||||
|
$enabledScope = Component::enabled();
|
||||||
|
$totalComponents = Component::enabled()->count();
|
||||||
|
$majorOutages = Component::enabled()->status(4)->count();
|
||||||
|
$isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false;
|
||||||
|
|
||||||
|
// Default data
|
||||||
|
$status = [
|
||||||
|
'system_status' => 'info',
|
||||||
|
'system_message' => trans_choice('cachet.service.bad', $totalComponents),
|
||||||
|
'favicon' => 'favicon-high-alert',
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($isMajorOutage) {
|
||||||
|
$status = [
|
||||||
|
'system_status' => 'danger',
|
||||||
|
'system_message' => trans_choice('cachet.service.major', $totalComponents),
|
||||||
|
'favicon' => 'favicon-high-alert',
|
||||||
|
];
|
||||||
|
} elseif (Component::enabled()->notStatus(1)->count() === 0) {
|
||||||
|
// If all our components are ok, do we have any non-fixed incidents?
|
||||||
|
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) {
|
||||||
|
return $incident->status > 0;
|
||||||
|
});
|
||||||
|
$incidentCount = $incidents->count();
|
||||||
|
|
||||||
|
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
|
||||||
|
$status = [
|
||||||
|
'system_status' => 'success',
|
||||||
|
'system_message' => trans_choice('cachet.service.good', $totalComponents),
|
||||||
|
'favicon' => 'favicon',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} elseif (Component::enabled()->whereIn('status', [2, 3])->count() > 0) {
|
||||||
|
$status['favicon'] = 'favicon-medium-alert';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -184,6 +184,7 @@ return [
|
|||||||
'CachetHQ\Cachet\Foundation\Providers\ComposerServiceProvider',
|
'CachetHQ\Cachet\Foundation\Providers\ComposerServiceProvider',
|
||||||
'CachetHQ\Cachet\Foundation\Providers\ConsoleServiceProvider',
|
'CachetHQ\Cachet\Foundation\Providers\ConsoleServiceProvider',
|
||||||
'CachetHQ\Cachet\Foundation\Providers\ConfigServiceProvider',
|
'CachetHQ\Cachet\Foundation\Providers\ConfigServiceProvider',
|
||||||
|
'CachetHQ\Cachet\Foundation\Providers\IntegrationServiceProvider',
|
||||||
'CachetHQ\Cachet\Foundation\Providers\EventServiceProvider',
|
'CachetHQ\Cachet\Foundation\Providers\EventServiceProvider',
|
||||||
'CachetHQ\Cachet\Foundation\Providers\RepositoryServiceProvider',
|
'CachetHQ\Cachet\Foundation\Providers\RepositoryServiceProvider',
|
||||||
'CachetHQ\Cachet\Foundation\Providers\RouteServiceProvider',
|
'CachetHQ\Cachet\Foundation\Providers\RouteServiceProvider',
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Cachet.
|
||||||
|
*
|
||||||
|
* (c) Alt Three Services Limited
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace CachetHQ\Tests\Cachet\Foundation\Providers;
|
||||||
|
|
||||||
|
use AltThree\TestBench\ServiceProviderTrait;
|
||||||
|
use CachetHQ\Cachet\Integrations\Contracts\System;
|
||||||
|
use CachetHQ\Tests\Cachet\AbstractTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the integration service provider test class.
|
||||||
|
*
|
||||||
|
* @author James Brooks <james@alt-three.com>
|
||||||
|
*/
|
||||||
|
class IntegrationServiceProviderTest extends AbstractTestCase
|
||||||
|
{
|
||||||
|
use ServiceProviderTrait;
|
||||||
|
|
||||||
|
public function testSystemIsInjectable()
|
||||||
|
{
|
||||||
|
$this->assertIsInjectable(System::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user