Rewrite the entire scheduled maintenance implementation

This commit is contained in:
James Brooks
2016-10-30 20:54:12 +00:00
parent a2cded299d
commit ebed68a7d8
57 changed files with 1989 additions and 512 deletions

View File

@@ -0,0 +1,128 @@
<?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\Http\Controllers\Api;
use CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\DeleteScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand;
use CachetHQ\Cachet\Models\Schedule;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* This is the schedule controller.
*
* @author James Brooks <james@alt-three.com>
*/
class ScheduleController extends AbstractApiController
{
/**
* Return all schedules.
*
* @return \Illuminate\Http\JsonResponse
*/
public function getSchedules()
{
$schedule = Schedule::whereRaw('1 = 1');
if ($sortBy = Binput::get('sort')) {
$direction = Binput::has('order') && Binput::get('order') == 'desc';
$schedule->sort($sortBy, $direction);
}
$schedule = $schedule->paginate(Binput::get('per_page', 20));
return $this->paginator($schedule, Request::instance());
}
/**
* Return a single schedule.
*
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\Http\JsonResponse
*/
public function getSchedule(Schedule $schedule)
{
return $this->item($schedule);
}
/**
* Create a new schedule.
*
* @return \Illuminate\Http\JsonResponse
*/
public function postSchedule()
{
try {
$schedule = dispatch(new CreateScheduleCommand(
Binput::get('name'),
Binput::get('message'),
Binput::get('status'),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($schedule);
}
/**
* Update a schedule.
*
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\Http\JsonResponse
*/
public function putSchedule(Schedule $schedule)
{
try {
$schedule = dispatch(new UpdateScheduleCommand(
$schedule,
Binput::get('name'),
Binput::get('message'),
Binput::get('status'),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($schedule);
}
/**
* Delete a schedule.
*
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteSchedule(Schedule $schedule)
{
try {
dispatch(new DeleteScheduleCommand($schedule));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->noContent();
}
}

View File

@@ -127,7 +127,7 @@ class DashboardController extends Controller
*/
protected function getIncidents()
{
$allIncidents = Incident::notScheduled()->whereBetween('occurred_at', [
$allIncidents = Incident::whereBetween('occurred_at', [
$this->startDate->copy()->subDays(30)->format('Y-m-d').' 00:00:00',
$this->startDate->format('Y-m-d').' 23:59:59',
])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {

View File

@@ -57,22 +57,6 @@ class IncidentController extends Controller
{
$this->auth = $auth;
$this->subMenu = [
'incidents' => [
'title' => trans('dashboard.incidents.incidents'),
'url' => cachet_route('dashboard.incidents'),
'icon' => 'ion-android-checkmark-circle',
'active' => true,
],
'schedule' => [
'title' => trans('dashboard.schedule.schedule'),
'url' => cachet_route('dashboard.schedule'),
'icon' => 'ion-android-calendar',
'active' => false,
],
];
View::share('sub_menu', $this->subMenu);
View::share('sub_title', trans('dashboard.incidents.title'));
}
@@ -83,7 +67,7 @@ class IncidentController extends Controller
*/
public function showIncidents()
{
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get();
$incidents = Incident::orderBy('created_at', 'desc')->get();
return View::make('dashboard.incidents.index')
->withPageTitle(trans('dashboard.incidents.incidents').' - '.trans('dashboard.dashboard'))

View File

@@ -12,16 +12,20 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use AltThree\Validator\ValidationException;
use CachetHQ\Cachet\Bus\Commands\Incident\ReportMaintenanceCommand;
use CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\DeleteScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand;
use CachetHQ\Cachet\Models\IncidentTemplate;
use CachetHQ\Cachet\Models\Schedule;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\View;
use Illuminate\Support\MessageBag;
use Jenssegers\Date\Date;
/**
* This is the schedule controller class.
*
* @author James Brooks <james@alt-three.com>
*/
class ScheduleController extends Controller
{
/**
@@ -38,23 +42,7 @@ class ScheduleController extends Controller
*/
public function __construct()
{
$this->subMenu = [
'incidents' => [
'title' => trans('dashboard.incidents.incidents'),
'url' => cachet_route('dashboard.incidents'),
'icon' => 'ion-android-checkmark-circle',
'active' => false,
],
'schedule' => [
'title' => trans('dashboard.schedule.schedule'),
'url' => cachet_route('dashboard.schedule'),
'icon' => 'ion-android-calendar',
'active' => true,
],
];
View::share('sub_menu', $this->subMenu);
View::share('sub_title', trans('dashboard.incidents.title'));
View::share('sub_title', trans('dashboard.schedule.title'));
}
/**
@@ -64,7 +52,7 @@ class ScheduleController extends Controller
*/
public function showIndex()
{
$schedule = Incident::scheduled()->orderBy('created_at')->get();
$schedule = Schedule::orderBy('created_at')->get();
return View::make('dashboard.schedule.index')
->withPageTitle(trans('dashboard.schedule.schedule').' - '.trans('dashboard.dashboard'))
@@ -86,18 +74,20 @@ class ScheduleController extends Controller
}
/**
* Creates a new scheduled maintenance "incident".
* Creates a new scheduled maintenance.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function addScheduleAction()
{
try {
$incident = dispatch(new ReportMaintenanceCommand(
dispatch(new CreateScheduleCommand(
Binput::get('name'),
Binput::get('message'),
Binput::get('notify'),
Binput::get('scheduled_at')
Binput::get('status', Schedule::UPCOMING),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
));
} catch (ValidationException $e) {
return cachet_redirect('dashboard.schedule.create')
@@ -113,11 +103,11 @@ class ScheduleController extends Controller
/**
* Shows the edit schedule maintenance form.
*
* @param \CachetHQ\Cachet\Models\Incident $schedule
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\View\View
*/
public function showEditSchedule(Incident $schedule)
public function showEditSchedule(Schedule $schedule)
{
$incidentTemplates = IncidentTemplate::all();
@@ -130,30 +120,22 @@ class ScheduleController extends Controller
/**
* Updates the given incident.
*
* @param \CachetHQ\Cachet\Models\Incident $schedule
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\Http\RedirectResponse
*/
public function editScheduleAction(Incident $schedule)
public function editScheduleAction(Schedule $schedule)
{
$scheduleData = Binput::get('incident');
// Parse the schedule date.
$scheduledAt = app(DateFactory::class)->create('d/m/Y H:i', $scheduleData['scheduled_at']);
if ($scheduledAt->isPast()) {
$messageBag = new MessageBag();
$messageBag->add('scheduled_at', trans('validation.date', ['attribute' => 'scheduled time you supplied']));
return cachet_redirect('dashboard.schedule.edit', [$schedule->id])->withErrors($messageBag);
}
$scheduleData['scheduled_at'] = $scheduledAt;
// Bypass the incident.status field.
$scheduleData['status'] = 0;
try {
$schedule->update($scheduleData);
$schedule = dispatch(new UpdateScheduleCommand(
$schedule,
Binput::get('name', null),
Binput::get('message', null),
Binput::get('status', null),
Binput::get('scheduled_at', null),
Binput::get('completed_at', null),
Binput::get('components', [])
));
} catch (ValidationException $e) {
return cachet_redirect('dashboard.schedule.edit', [$schedule->id])
->withInput(Binput::all())
@@ -168,13 +150,13 @@ class ScheduleController extends Controller
/**
* Deletes a given schedule.
*
* @param \CachetHQ\Cachet\Models\Incident $schedule
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deleteScheduleAction(Incident $schedule)
public function deleteScheduleAction(Schedule $schedule)
{
$schedule->delete();
dispatch(new DeleteScheduleCommand($schedule));
return cachet_redirect('dashboard.schedule')
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.schedule.delete.success')));

View File

@@ -17,6 +17,7 @@ use CachetHQ\Cachet\Http\Controllers\Api\AbstractApiController;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\Schedule;
use CachetHQ\Cachet\Repositories\Metric\MetricRepository;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
@@ -84,11 +85,11 @@ class StatusPageController extends AbstractApiController
$incidentVisibility = Auth::check() ? 0 : 1;
$allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisibility)->whereBetween('occurred_at', [
$allIncidents = Incident::where('visible', '>=', $incidentVisibility)->whereBetween('occurred_at', [
$startDate->copy()->subDays($daysToShow)->format('Y-m-d').' 00:00:00',
$startDate->format('Y-m-d').' 23:59:59',
])->orderBy('scheduled_at', 'desc')->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {
return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->occurred_at)->toDateString();
])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {
return app(DateFactory::class)->make($incident->occurred_at)->toDateString();
});
// Add in days that have no incidents
@@ -111,7 +112,7 @@ class StatusPageController extends AbstractApiController
->withDaysToShow($daysToShow)
->withAllIncidents($allIncidents)
->withCanPageForward((bool) $today->gt($startDate))
->withCanPageBackward(Incident::notScheduled()->where('occurred_at', '<', $startDate->format('Y-m-d'))->count() > 0)
->withCanPageBackward(Incident::where('occurred_at', '<', $startDate->format('Y-m-d'))->count() > 0)
->withPreviousDate($startDate->copy()->subDays($daysToShow)->toDateString())
->withNextDate($startDate->copy()->addDays($daysToShow)->toDateString());
}
@@ -125,8 +126,19 @@ class StatusPageController extends AbstractApiController
*/
public function showIncident(Incident $incident)
{
return View::make('single-incident')
->withIncident($incident);
return View::make('single-incident')->withIncident($incident);
}
/**
* Show a single schedule.
*
* @param \CachetHQ\Cachet\Models\Schedule $schedule
*
* @return \Illuminate\View\View
*/
public function showSchedule(Schedule $schedule)
{
return View::make('single-schedule')->withSchedule($schedule);
}
/**

View File

@@ -59,6 +59,9 @@ class ApiRoutes
$router->get('metrics', 'MetricController@getMetrics');
$router->get('metrics/{metric}', 'MetricController@getMetric');
$router->get('metrics/{metric}/points', 'MetricController@getMetricPoints');
$router->get('schedules', 'ScheduleController@getSchedules');
$router->get('schedules/{schedule}', 'ScheduleController@getSchedule');
});
$router->group(['middleware' => ['auth.api:true']], function (Registrar $router) {
@@ -70,6 +73,7 @@ class ApiRoutes
$router->post('incidents/{incident}/updates', 'IncidentUpdateController@postIncidentUpdate');
$router->post('metrics', 'MetricController@postMetrics');
$router->post('metrics/{metric}/points', 'MetricPointController@postMetricPoints');
$router->post('schedules', 'ScheduleController@postSchedule');
$router->post('subscribers', 'SubscriberController@postSubscribers');
$router->put('components/groups/{component_group}', 'ComponentGroupController@putGroup');
@@ -78,6 +82,7 @@ class ApiRoutes
$router->put('incidents/{incident}/updates/{update}', 'IncidentUpdateController@putIncidentUpdate');
$router->put('metrics/{metric}', 'MetricController@putMetric');
$router->put('metrics/{metric}/points/{metric_point}', 'MetricPointController@putMetricPoint');
$router->put('schedules/{schedule}', 'ScheduleController@putSchedule');
$router->delete('components/groups/{component_group}', 'ComponentGroupController@deleteGroup');
$router->delete('components/{component}', 'ComponentController@deleteComponent');
@@ -85,6 +90,7 @@ class ApiRoutes
$router->delete('incidents/{incident}/updates/{update}', 'IncidentUpdateController@deleteIncidentUpdate');
$router->delete('metrics/{metric}', 'MetricController@deleteMetric');
$router->delete('metrics/{metric}/points/{metric_point}', 'MetricPointController@deleteMetricPoint');
$router->delete('schedules/{schedule}', 'ScheduleController@deleteSchedule');
$router->delete('subscribers/{subscriber}', 'SubscriberController@deleteSubscriber');
$router->delete('subscriptions/{subscription}', 'SubscriberController@deleteSubscription');
});

View File

@@ -56,15 +56,15 @@ class ScheduleRoutes
'uses' => 'ScheduleController@addScheduleAction',
]);
$router->get('{incident}', [
$router->get('{schedule}', [
'as' => 'get:dashboard.schedule.edit',
'uses' => 'ScheduleController@showEditSchedule',
]);
$router->post('{incident}', [
$router->post('{schedule}', [
'as' => 'post:dashboard.schedule.edit',
'uses' => 'ScheduleController@editScheduleAction',
]);
$router->delete('{incident}', [
$router->delete('{schedule}', [
'as' => 'delete:dashboard.schedule.delete',
'uses' => 'ScheduleController@deleteScheduleAction',
]);

View File

@@ -49,6 +49,11 @@ class StatusPageRoutes
'uses' => 'StatusPageController@showIncident',
]);
$router->get('schedules/{schedule}', [
'as' => 'get:schedule',
'uses' => 'StatusPageController@showSchedule',
]);
$router->get('metrics/{metric}', [
'as' => 'get:metric',
'uses' => 'StatusPageController@getMetrics',