diff --git a/app/Bus/Commands/Incident/ReportIncidentCommand.php b/app/Bus/Commands/Incident/ReportIncidentCommand.php index d74df68e5eb3..979cc0cdcda1 100644 --- a/app/Bus/Commands/Incident/ReportIncidentCommand.php +++ b/app/Bus/Commands/Incident/ReportIncidentCommand.php @@ -76,11 +76,11 @@ final class ReportIncidentCommand public $stickied; /** - * The date at which the incident occurred. + * The date at which the incident occurred at. * * @var string|null */ - public $incident_date; + public $occurred_at; /** * A given incident template. @@ -110,7 +110,7 @@ final class ReportIncidentCommand 'component_status' => 'nullable|required_with:component_id|int|min:0|max:4', 'notify' => 'nullable|bool', 'stickied' => 'required|bool', - 'incident_date' => 'nullable|string', + 'occurred_at' => 'nullable|string', 'template' => 'nullable|string', ]; @@ -125,13 +125,13 @@ final class ReportIncidentCommand * @param int $component_status * @param bool $notify * @param bool $stickied - * @param string|null $incident_date + * @param string|null $occurred_at * @param string|null $template * @param array $template_vars * * @return void */ - public function __construct($name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $incident_date, $template, array $template_vars = []) + public function __construct($name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $occurred_at, $template, array $template_vars = []) { $this->name = $name; $this->status = $status; @@ -141,7 +141,7 @@ public function __construct($name, $status, $message, $visible, $component_id, $ $this->component_status = $component_status; $this->notify = $notify; $this->stickied = $stickied; - $this->incident_date = $incident_date; + $this->occurred_at = $occurred_at; $this->template = $template; $this->template_vars = $template_vars; } diff --git a/app/Bus/Commands/Incident/UpdateIncidentCommand.php b/app/Bus/Commands/Incident/UpdateIncidentCommand.php index e9fd1a404c40..36036e6d9637 100644 --- a/app/Bus/Commands/Incident/UpdateIncidentCommand.php +++ b/app/Bus/Commands/Incident/UpdateIncidentCommand.php @@ -13,6 +13,13 @@ use CachetHQ\Cachet\Models\Incident; +/** + * This is the update incident command. + * + * @author James Brooks + * @author Joseph Cohem + * @author Graham Campbell + */ final class UpdateIncidentCommand { /** @@ -79,11 +86,11 @@ final class UpdateIncidentCommand public $stickied; /** - * The date that the incident occurred on. + * The timestamp that the incident occurred at. * - * @var string + * @var string|null */ - public $incident_date; + public $occurred_at; /** * A given incident template. @@ -113,6 +120,7 @@ final class UpdateIncidentCommand 'component_status' => 'nullable|int|min:0|max:4|required_with:component_id', 'notify' => 'nullable|bool', 'stickied' => 'nullable|bool', + 'occurred_at' => 'nullable|string', 'template' => 'nullable|string', ]; @@ -128,13 +136,13 @@ final class UpdateIncidentCommand * @param int $component_status * @param bool $notify * @param bool $stickied - * @param string|null $incident_date + * @param string|null $occurred_at * @param string|null $template * @param array $template_vars * * @return void */ - public function __construct(Incident $incident, $name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $incident_date, $template, array $template_vars = []) + public function __construct(Incident $incident, $name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $occurred_at, $template, array $template_vars = []) { $this->incident = $incident; $this->name = $name; @@ -145,7 +153,7 @@ public function __construct(Incident $incident, $name, $status, $message, $visib $this->component_status = $component_status; $this->notify = $notify; $this->stickied = $stickied; - $this->incident_date = $incident_date; + $this->occurred_at = $occurred_at; $this->template = $template; $this->template_vars = $template_vars; } diff --git a/app/Bus/Exceptions/Incident/InvalidIncidentTimestampException.php b/app/Bus/Exceptions/Incident/InvalidIncidentTimestampException.php new file mode 100644 index 000000000000..3843c180fa75 --- /dev/null +++ b/app/Bus/Exceptions/Incident/InvalidIncidentTimestampException.php @@ -0,0 +1,25 @@ + + */ +class InvalidIncidentTimestampException extends Exception implements ExceptionInterface +{ + // +} diff --git a/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php index 28271b72e5a2..3a512f70cf3c 100644 --- a/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php @@ -14,6 +14,7 @@ use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\ReportIncidentCommand; use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent; +use CachetHQ\Cachet\Bus\Exceptions\Incident\InvalidIncidentTimestampException; use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Incident; @@ -75,11 +76,12 @@ public function handle(ReportIncidentCommand $command) } // The incident occurred at a different time. - if ($command->incident_date) { - $incidentDate = $this->dates->create('d/m/Y H:i', $command->incident_date); - - $data['created_at'] = $incidentDate; - $data['updated_at'] = $incidentDate; + if ($occurredAt = $command->occurredAt) { + if ($date = $this->dates->create('Y-m-d H:i', $occurredAt)) { + $incident->fill(['occurred_at' => $date]); + } else { + throw new InvalidIncidentTimestampException("Unable to pass timestamp {$occurredAt}"); + } } // Create the incident @@ -127,7 +129,7 @@ protected function parseTemplate(IncidentTemplate $template, ReportIncidentComma 'visible' => $command->visible, 'notify' => $command->notify, 'stickied' => $command->stickied, - 'incident_date' => $command->incident_date, + 'occurredAt' => $command->occurredAt, 'component' => Component::find($command->component_id) ?: null, 'component_status' => $command->component_status, ], diff --git a/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php index 665e49a8c8cd..64117958d04b 100644 --- a/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php @@ -14,6 +14,7 @@ use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand; use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent; +use CachetHQ\Cachet\Bus\Exceptions\Incident\InvalidIncidentTimestampException; use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Incident; @@ -61,18 +62,20 @@ public function handle(UpdateIncidentCommand $command) } $incident = $command->incident; - $incident->update($this->filter($command)); + $incident->fill($this->filter($command)); // The incident occurred at a different time. - if ($command->incident_date) { - $incidentDate = $this->dates->create('d/m/Y H:i', $command->incident_date); - - $incident->update([ - 'created_at' => $incidentDate, - 'updated_at' => $incidentDate, - ]); + if ($occurredAt = $command->occurredAt) { + if ($date = $this->dates->create('Y-m-d H:i', $occurredAt)) { + $incident->fill(['occurred_at' => $date]); + } else { + throw new InvalidIncidentTimestampException("Unable to pass timestamp {$occurredAt}"); + } } + // Rather than making lots of updates, just fill and save. + $incident->save(); + // Update the component. if ($component = Component::find($command->component_id)) { dispatch(new UpdateComponentCommand( @@ -138,7 +141,7 @@ protected function parseTemplate(IncidentTemplate $template, UpdateIncidentComma 'visible' => $command->visible, 'notify' => $command->notify, 'stickied' => $command->stickied, - 'incident_date' => $command->incident_date, + 'occurredAt' => $command->occurredAt, 'component' => Component::find($command->component_id) ?: null, 'component_status' => $command->component_status, ], diff --git a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php index 24b10c7d0e70..13a6e68d5790 100644 --- a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php @@ -114,7 +114,7 @@ public function notify(IncidentWasReportedEvent $event, $subscriber) 'has_component' => ($event->incident->component) ? true : false, 'component_name' => $component ? $component->name : null, 'name' => $incident->name, - 'timestamp' => $incident->created_at_formatted, + 'timestamp' => $incident->occurred_at_formatted, 'status' => $incident->human_status, 'html_content' => $incident->formattedMessage, 'text_content' => $incident->message, diff --git a/app/Composers/Modules/StickiedComposer.php b/app/Composers/Modules/StickiedComposer.php index 084c9ff61b42..bd599c72fe38 100644 --- a/app/Composers/Modules/StickiedComposer.php +++ b/app/Composers/Modules/StickiedComposer.php @@ -33,8 +33,8 @@ class StickiedComposer */ public function compose(View $view) { - $stickiedIncidents = Incident::stickied()->orderBy('scheduled_at', 'desc')->orderBy('created_at', 'desc')->get()->groupBy(function (Incident $incident) { - return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->created_at)->toDateString(); + $stickiedIncidents = Incident::stickied()->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(); }); $view->withStickiedIncidents($stickiedIncidents); } diff --git a/app/Console/Commands/DemoSeederCommand.php b/app/Console/Commands/DemoSeederCommand.php index 477e02b610bd..f5581d8c94de 100644 --- a/app/Console/Commands/DemoSeederCommand.php +++ b/app/Console/Commands/DemoSeederCommand.php @@ -21,6 +21,7 @@ use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\User; use CachetHQ\Cachet\Settings\Repository; +use Carbon\Carbon; use DateInterval; use DateTime; use Illuminate\Console\Command; @@ -209,6 +210,7 @@ protected function seedIncidents() 'scheduled_at' => null, 'visible' => 1, 'stickied' => false, + 'occurred_at' => Carbon::now(), ], [ 'name' => 'This is an unresolved incident', @@ -218,6 +220,7 @@ protected function seedIncidents() 'scheduled_at' => null, 'visible' => 1, 'stickied' => false, + 'occurred_at' => Carbon::now(), ], ]; diff --git a/app/Http/Controllers/Api/IncidentController.php b/app/Http/Controllers/Api/IncidentController.php index 2d843710c556..a7a9bfb65f30 100644 --- a/app/Http/Controllers/Api/IncidentController.php +++ b/app/Http/Controllers/Api/IncidentController.php @@ -76,7 +76,7 @@ public function postIncidents() Binput::get('component_status'), Binput::get('notify', true), Binput::get('stickied', false), - Binput::get('created_at'), + Binput::get('occurred_at'), Binput::get('template'), Binput::get('vars', []) )); @@ -107,7 +107,7 @@ public function putIncident(Incident $incident) Binput::get('component_status'), Binput::get('notify', true), Binput::get('stickied', false), - Binput::get('created_at'), + Binput::get('occurred_at'), Binput::get('template'), Binput::get('vars', []) )); diff --git a/app/Http/Controllers/Dashboard/DashboardController.php b/app/Http/Controllers/Dashboard/DashboardController.php index a0ee0df6a819..0597ca3f2fea 100644 --- a/app/Http/Controllers/Dashboard/DashboardController.php +++ b/app/Http/Controllers/Dashboard/DashboardController.php @@ -127,11 +127,11 @@ public function showDashboard() */ protected function getIncidents() { - $allIncidents = Incident::notScheduled()->whereBetween('created_at', [ + $allIncidents = Incident::notScheduled()->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('created_at', 'desc')->get()->groupBy(function (Incident $incident) { - return (new Date($incident->created_at)) + ])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) { + return (new Date($incident->occurred_at)) ->setTimezone($this->dateTimeZone)->toDateString(); }); diff --git a/app/Http/Controllers/Dashboard/IncidentController.php b/app/Http/Controllers/Dashboard/IncidentController.php index 3c3b44c9a2b4..8e5bf34ac7bc 100644 --- a/app/Http/Controllers/Dashboard/IncidentController.php +++ b/app/Http/Controllers/Dashboard/IncidentController.php @@ -133,7 +133,7 @@ public function createIncidentAction() Binput::get('component_status'), Binput::get('notify', false), Binput::get('stickied', false), - Binput::get('created_at'), + Binput::get('occurred_at'), null, [] )); @@ -259,7 +259,7 @@ public function editIncidentAction(Incident $incident) Binput::get('component_status'), Binput::get('notify', true), Binput::get('stickied', false), - Binput::get('created_at'), + Binput::get('occurred_at'), null, [] )); diff --git a/app/Http/Controllers/FeedController.php b/app/Http/Controllers/FeedController.php index 3d1c6ca2649b..1cf96e2b76c4 100644 --- a/app/Http/Controllers/FeedController.php +++ b/app/Http/Controllers/FeedController.php @@ -18,6 +18,11 @@ use Illuminate\Support\Facades\Config; use Illuminate\Support\Str; +/** + * This is the feed controller. + * + * @author James Brooks + */ class FeedController extends Controller { /** @@ -80,12 +85,12 @@ private function feedAction(ComponentGroup &$group, $isRss) { if ($group->exists) { $group->components->map(function ($component) use ($isRss) { - $component->incidents()->visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($isRss) { + $component->incidents()->visible()->orderBy('occurred_at', 'desc')->get()->map(function ($incident) use ($isRss) { $this->feedAddItem($incident, $isRss); }); }); } else { - Incident::visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($isRss) { + Incident::visible()->orderBy('occurred_at', 'desc')->get()->map(function ($incident) use ($isRss) { $this->feedAddItem($incident, $isRss); }); } @@ -105,7 +110,7 @@ private function feedAddItem(Incident $incident, $isRss) $incident->name, Config::get('setting.app_name'), Str::canonicalize(cachet_route('incident', [$incident->id])), - $isRss ? $incident->created_at->toRssString() : $incident->created_at->toAtomString(), + $isRss ? $incident->occurred_at->toRssString() : $incident->occurred_at->toAtomString(), $isRss ? $incident->message : Markdown::convertToHtml($incident->message) ); } diff --git a/app/Http/Controllers/StatusPageController.php b/app/Http/Controllers/StatusPageController.php index 3c8feffe69df..5ae8717b18cc 100644 --- a/app/Http/Controllers/StatusPageController.php +++ b/app/Http/Controllers/StatusPageController.php @@ -82,11 +82,11 @@ public function showIndex() $incidentVisibility = Auth::check() ? 0 : 1; - $allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisibility)->whereBetween('created_at', [ + $allIncidents = Incident::notScheduled()->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('created_at', 'desc')->get()->load('updates')->groupBy(function (Incident $incident) { - return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->created_at)->toDateString(); + ])->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(); }); // Add in days that have no incidents @@ -109,7 +109,7 @@ public function showIndex() ->withDaysToShow($daysToShow) ->withAllIncidents($allIncidents) ->withCanPageForward((bool) $today->gt($startDate)) - ->withCanPageBackward(Incident::notScheduled()->where('created_at', '<', $startDate->format('Y-m-d'))->count() > 0) + ->withCanPageBackward(Incident::notScheduled()->where('occurred_at', '<', $startDate->format('Y-m-d'))->count() > 0) ->withPreviousDate($startDate->copy()->subDays($daysToShow)->toDateString()) ->withNextDate($startDate->copy()->addDays($daysToShow)->toDateString()); } diff --git a/app/Integrations/Core/System.php b/app/Integrations/Core/System.php index 77395af6b2da..0b83a8e6c8a2 100644 --- a/app/Integrations/Core/System.php +++ b/app/Integrations/Core/System.php @@ -49,7 +49,7 @@ public function getStatus() ]; } elseif ($enabledScope->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) { + $incidents = Incident::notScheduled()->orderBy('occurred_at', 'desc')->get()->filter(function ($incident) { return $incident->status > 0; }); $incidentCount = $incidents->count(); diff --git a/app/Models/Incident.php b/app/Models/Incident.php index 10ff79b133ff..ba396b8cf619 100644 --- a/app/Models/Incident.php +++ b/app/Models/Incident.php @@ -21,6 +21,13 @@ use Illuminate\Database\Eloquent\SoftDeletes; use McCool\LaravelAutoPresenter\HasPresenter; +/** + * This is the incident model. + * + * @author James Brooks + * @author Joseph Cohen + * @author Graham Campbell + */ class Incident extends Model implements HasPresenter { use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait; @@ -71,6 +78,7 @@ class Incident extends Model implements HasPresenter 'visible' => 'int', 'stickied' => 'bool', 'scheduled_at' => 'date', + 'occurred_at' => 'date', 'deleted_at' => 'date', ]; @@ -87,6 +95,7 @@ class Incident extends Model implements HasPresenter 'stickied', 'message', 'scheduled_at', + 'occurred_at', 'created_at', 'updated_at', ]; @@ -131,6 +140,7 @@ class Incident extends Model implements HasPresenter 'visible', 'stickied', 'message', + 'occurred_at', ]; /** diff --git a/app/Presenters/IncidentPresenter.php b/app/Presenters/IncidentPresenter.php index a552f5784033..17e65a825c3f 100644 --- a/app/Presenters/IncidentPresenter.php +++ b/app/Presenters/IncidentPresenter.php @@ -12,16 +12,23 @@ namespace CachetHQ\Cachet\Presenters; use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait; use GrahamCampbell\Markdown\Facades\Markdown; use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Support\Facades\Config; use McCool\LaravelAutoPresenter\BasePresenter; class IncidentPresenter extends BasePresenter implements Arrayable { use TimestampsTrait; + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Dates\DateFactory + */ + protected $dates; + /** * Inciden icon lookup. * @@ -35,6 +42,21 @@ class IncidentPresenter extends BasePresenter implements Arrayable 4 => 'icon ion-checkmark greens', // Fixed ]; + /** + * Create a new presenter. + * + * @param \CachetHQ\Cachet\Dates\DateFactory $dates + * @param \CachetHQ\Cachet\Models\Incident $resource + * + * @return void + */ + public function __construct(DateFactory $dates, Incident $resource) + { + $this->dates = $dates; + + parent::__construct($resource); + } + /** * Renders the message from Markdown into HTML. * @@ -55,14 +77,24 @@ public function raw_message() return strip_tags($this->formattedMessage()); } + /** + * Present formatted occurred_at date time. + * + * @return string + */ + public function occurred_at() + { + return $this->dates->make($this->wrappedObject->occurred_at)->toDateTimeString(); + } + /** * Present diff for humans date time. * * @return string */ - public function created_at_diff() + public function occurred_at_diff() { - return app(DateFactory::class)->make($this->wrappedObject->created_at)->diffForHumans(); + return $this->dates->make($this->wrappedObject->occurred_at)->diffForHumans(); } /** @@ -70,19 +102,49 @@ public function created_at_diff() * * @return string */ - public function created_at_formatted() + public function occurred_at_formatted() { - return ucfirst(app(DateFactory::class)->make($this->wrappedObject->created_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s'))); + return ucfirst($this->dates->make($this->wrappedObject->occurred_at)->format($this->incidentDateFormat())); } /** - * Formats the created_at time ready to be used by bootstrap-datetimepicker. + * Formats the occurred_at time ready to be used by bootstrap-datetimepicker. * * @return string */ - public function created_at_datetimepicker() + public function occurred_at_datetimepicker() + { + return $this->dates->make($this->wrappedObject->occurred_at)->format('Y-m-d H:i'); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function occurred_at_iso() + { + return $this->dates->make($this->wrappedObject->occurred_at)->toISO8601String(); + } + + /** + * Present diff for humans date time. + * + * @return string + */ + public function created_at_diff() + { + return $this->dates->make($this->wrappedObject->created_at)->diffForHumans(); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function created_at_formatted() { - return app(DateFactory::class)->make($this->wrappedObject->created_at)->format('d/m/Y H:i'); + return ucfirst($this->dates->make($this->wrappedObject->created_at)->format($this->incidentDateFormat())); } /** @@ -92,7 +154,7 @@ public function created_at_datetimepicker() */ public function created_at_iso() { - return app(DateFactory::class)->make($this->wrappedObject->created_at)->toISO8601String(); + return $this->dates->make($this->wrappedObject->created_at)->toISO8601String(); } /** @@ -102,7 +164,7 @@ public function created_at_iso() */ public function scheduled_at() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->toDateTimeString(); + return $this->dates->make($this->wrappedObject->scheduled_at)->toDateTimeString(); } /** @@ -112,7 +174,7 @@ public function scheduled_at() */ public function scheduled_at_diff() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->diffForHumans(); + return $this->dates->make($this->wrappedObject->scheduled_at)->diffForHumans(); } /** @@ -122,7 +184,7 @@ public function scheduled_at_diff() */ public function scheduled_at_formatted() { - return ucfirst(app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s'))); + return ucfirst($this->dates->make($this->wrappedObject->scheduled_at)->format($this->incidentDateFormat())); } /** @@ -132,7 +194,7 @@ public function scheduled_at_formatted() */ public function scheduled_at_iso() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->toISO8601String(); + return $this->dates->make($this->wrappedObject->scheduled_at)->toISO8601String(); } /** @@ -142,7 +204,7 @@ public function scheduled_at_iso() */ public function scheduled_at_datetimepicker() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->format('d/m/Y H:i'); + return $this->dates->make($this->wrappedObject->scheduled_at)->format('d/m/Y H:i'); } /** @@ -156,7 +218,7 @@ public function timestamp_formatted() return $this->scheduled_at_formatted; } - return $this->created_at_formatted; + return $this->occurred_at_formatted; } /** @@ -170,7 +232,7 @@ public function timestamp_iso() return $this->scheduled_at_iso; } - return $this->created_at_iso; + return $this->occurred_at_iso; } /** @@ -269,7 +331,7 @@ public function permalink() public function duration() { if ($update = $this->latest()) { - return $this->wrappedObject->created_at->diffInSeconds($update->created_at); + return $this->wrappedObject->created_at->diffInSeconds($update->occurred_at); } return 0; @@ -291,6 +353,7 @@ public function toArray() 'permalink' => $this->permalink(), 'duration' => $this->duration(), 'scheduled_at' => $this->scheduled_at(), + 'occurred_at' => $this->occurred_at(), 'created_at' => $this->created_at(), 'updated_at' => $this->updated_at(), ]); diff --git a/app/Presenters/Traits/TimestampsTrait.php b/app/Presenters/Traits/TimestampsTrait.php index eba58b2abdb9..56553e213403 100644 --- a/app/Presenters/Traits/TimestampsTrait.php +++ b/app/Presenters/Traits/TimestampsTrait.php @@ -12,7 +12,15 @@ namespace CachetHQ\Cachet\Presenters\Traits; use CachetHQ\Cachet\Dates\DateFactory; +use Illuminate\Support\Facades\Config; +/** + * This is the timestamps trait. + * + * @author Joseph Cohen + * @author Graham Campbell + * @author James Brooks + */ trait TimestampsTrait { /** @@ -44,4 +52,14 @@ public function deleted_at() { return app(DateFactory::class)->make($this->wrappedObject->deleted_at)->toDateTimeString(); } + + /** + * Get the incident date format setting, or fallback to a sane default. + * + * @return string + */ + protected function incidentDateFormat() + { + return Config::get('setting.incident_date_format', 'l jS F Y H:i:s'); + } } diff --git a/app/helpers.php b/app/helpers.php index 23260d9558bd..cae1f908d943 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -177,3 +177,61 @@ function cachet_redirect($name, $parameters = [], $status = 302, $headers = [], return app('redirect')->to($url, $status, $headers); } } + +if (!function_exists('datetime_to_moment')) { + /** + * Convert PHP datetimes to moment.js formats. + * + * Thanks to http://stackoverflow.com/a/30192680/394013 + * + * @param string $format + * + * @return string + */ + function datetime_to_moment($format) + { + $replacements = [ + 'd' => 'DD', + 'D' => 'ddd', + 'j' => 'D', + 'l' => 'dddd', + 'N' => 'E', + 'S' => 'o', + 'w' => 'e', + 'z' => 'DDD', + 'W' => 'W', + 'F' => 'MMMM', + 'm' => 'MM', + 'M' => 'MMM', + 'n' => 'M', + 't' => '', // no equivalent + 'L' => '', // no equivalent + 'o' => 'YYYY', + 'Y' => 'YYYY', + 'y' => 'YY', + 'a' => 'a', + 'A' => 'A', + 'B' => '', // no equivalent + 'g' => 'h', + 'G' => 'H', + 'h' => 'hh', + 'H' => 'HH', + 'i' => 'mm', + 's' => 'ss', + 'u' => 'SSS', + 'e' => 'zz', // deprecated since version 1.6.0 of moment.js + 'I' => '', // no equivalent + 'O' => '', // no equivalent + 'P' => '', // no equivalent + 'T' => '', // no equivalent + 'Z' => '', // no equivalent + 'c' => '', // no equivalent + 'r' => '', // no equivalent + 'U' => 'X', + ]; + + $momentFormat = strtr($format, $replacements); + + return $momentFormat; + } +} diff --git a/database/migrations/2016_10_24_183415_AlterTableIncidentsAddOccurredAtColumn.php b/database/migrations/2016_10_24_183415_AlterTableIncidentsAddOccurredAtColumn.php new file mode 100644 index 000000000000..8a7f76effab6 --- /dev/null +++ b/database/migrations/2016_10_24_183415_AlterTableIncidentsAddOccurredAtColumn.php @@ -0,0 +1,45 @@ +timestamp('occurred_at')->nullable()->after('scheduled_at'); + }); + + // We need a better way of handling data migrations... + DB::update('UPDATE incidents SET `occurred_at` = `created_at`'); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('incidents', function (Blueprint $table) { + $table->dropColumn('occurred_at'); + }); + } +} diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index 9366f21d8d0e..9b294d771811 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -161,6 +161,20 @@ $(function() { } }); + $('input[rel=datepicker-custom]').datetimepicker({ + sideBySide: true, + icons: { + time: 'ion-clock', + date: 'ion-android-calendar', + up: 'ion-ios-arrow-up', + down: 'ion-ios-arrow-down', + previous: 'ion-ios-arrow-left', + next: 'ion-ios-arrow-right', + today: 'ion-android-home', + clear: 'ion-trash-a', + } + }); + // Sortable models. var orderableLists = document.querySelectorAll('[data-orderable-list]'); diff --git a/resources/lang/en/forms.php b/resources/lang/en/forms.php index cc85c86ae22c..f85371c56290 100644 --- a/resources/lang/en/forms.php +++ b/resources/lang/en/forms.php @@ -52,7 +52,7 @@ 'message' => 'Message', 'message-help' => 'You may also use Markdown.', 'scheduled_at' => 'When to schedule the maintenance for?', - 'incident_time' => 'When did this incident occur?', + 'occurred_at' => 'When did this incident occur?', 'notify_subscribers' => 'Notify subscribers?', 'visibility' => 'Incident Visibility', 'stick_status' => 'Stick Incident', diff --git a/resources/views/dashboard/incidents/add.blade.php b/resources/views/dashboard/incidents/add.blade.php index 7c1118dcee48..b1548f9a3782 100644 --- a/resources/views/dashboard/incidents/add.blade.php +++ b/resources/views/dashboard/incidents/add.blade.php @@ -111,8 +111,8 @@
- {{ trans('forms.optional') }} - + {{ trans('forms.optional') }} +
@if(subscribers_enabled()) diff --git a/resources/views/dashboard/incidents/edit.blade.php b/resources/views/dashboard/incidents/edit.blade.php index afd1fb4af778..ac9602346f86 100644 --- a/resources/views/dashboard/incidents/edit.blade.php +++ b/resources/views/dashboard/incidents/edit.blade.php @@ -84,13 +84,11 @@
- {{ trans('forms.optional') }} - + {{ trans('forms.optional') }} +
- id}}> -
diff --git a/resources/views/single-incident.blade.php b/resources/views/single-incident.blade.php index ff97c9338abe..5fb2f94b534e 100644 --- a/resources/views/single-incident.blade.php +++ b/resources/views/single-incident.blade.php @@ -7,7 +7,7 @@ @stop @section('content') -

{{ $incident->name }} {{ formatted_date($incident->created_at) }}

+

{{ $incident->name }} {{ $incident->occurred_at_formatted }}


diff --git a/tests/Bus/Commands/Incident/ReportIncidentCommandTest.php b/tests/Bus/Commands/Incident/ReportIncidentCommandTest.php index 6cffe52cb96d..3c135c078999 100644 --- a/tests/Bus/Commands/Incident/ReportIncidentCommandTest.php +++ b/tests/Bus/Commands/Incident/ReportIncidentCommandTest.php @@ -37,7 +37,7 @@ protected function getObjectAndParams() 'component_status' => 1, 'notify' => false, 'stickied' => false, - 'incident_date' => null, + 'occurred_at' => null, 'template' => null, 'template_vars' => [], ]; @@ -51,7 +51,7 @@ protected function getObjectAndParams() $params['component_status'], $params['notify'], $params['stickied'], - $params['incident_date'], + $params['occurred_at'], $params['template'], $params['template_vars'] ); diff --git a/tests/Bus/Commands/Incident/UpdateIncidentCommandTest.php b/tests/Bus/Commands/Incident/UpdateIncidentCommandTest.php index 0294eb56f6d3..c09ca3aa67f0 100644 --- a/tests/Bus/Commands/Incident/UpdateIncidentCommandTest.php +++ b/tests/Bus/Commands/Incident/UpdateIncidentCommandTest.php @@ -39,7 +39,7 @@ protected function getObjectAndParams() 'component_status' => 1, 'notify' => false, 'stickied' => false, - 'incident_date' => null, + 'occurred_at' => null, 'template' => null, 'template_vars' => [], ]; @@ -54,7 +54,7 @@ protected function getObjectAndParams() $params['component_status'], $params['notify'], $params['stickied'], - $params['incident_date'], + $params['occurred_at'], $params['template'], $params['template_vars'] );