Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

incident doesn't update with update status (#219) #256

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/Actions/Incident/SetLatestStatusIncident.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Cachet\Actions\Incident;

use Cachet\Enums\IncidentStatusEnum;
use Cachet\Events\Incidents\IncidentUpdated;
use Cachet\Models\Incident;
use Cachet\Models\Update;

class SetLatestStatusIncident
{
/**
* Handle the action.
*/
public function handle(Incident $incident): Incident
{
/** @var Update|null $update */
$update = $incident->updates()->latest()->limit(1)->first();

if(is_null($update) && $incident->status === IncidentStatusEnum::unknown) {
return $incident;
}

$newStatus = $update->status ?? IncidentStatusEnum::unknown;

if($newStatus === $incident->status) {
return $incident;
}


$incident->update(['status' => $newStatus]);
IncidentUpdated::dispatch($incident);
return $incident->fresh();
}
}
6 changes: 5 additions & 1 deletion src/Actions/Update/CreateUpdate.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Cachet\Data\Requests\IncidentUpdate\CreateIncidentUpdateRequestData;
use Cachet\Data\Requests\ScheduleUpdate\CreateScheduleUpdateRequestData;
use Cachet\Events\Incidents\IncidentUpdated;
use Cachet\Models\Incident;
use Cachet\Models\Schedule;
use Cachet\Models\Update;
Expand All @@ -19,7 +20,10 @@ public function handle(Incident|Schedule $resource, CreateIncidentUpdateRequestD

$resource->updates()->save($update);

// @todo Dispatch notification that incident was updated.
if($resource instanceof Incident) {
$resource->update(['status' => $update->status]);
IncidentUpdated::dispatch($resource);
}

return $update;
}
Expand Down
1 change: 0 additions & 1 deletion src/Filament/Resources/IncidentResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class IncidentResource extends Resource
protected static ?string $model = Incident::class;

protected static ?string $navigationIcon = 'cachet-incident';

public static function form(Form $form): Form
{
return $form
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@

namespace Cachet\Filament\Resources\UpdateResource\RelationManagers;

use Cachet\Actions\Incident\SetLatestStatusIncident;
use Cachet\Actions\Update\CreateUpdate as CreateUpdateAction;
use Cachet\Data\Requests\IncidentUpdate\CreateIncidentUpdateRequestData;
use Cachet\Data\Requests\ScheduleUpdate\CreateScheduleUpdateRequestData;
use Cachet\Enums\IncidentStatusEnum;
use Cachet\Models\Incident;
use Cachet\Models\Schedule;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
use PHPUnit\Runner\ErrorException;

class UpdatesRelationManager extends RelationManager
{
Expand Down Expand Up @@ -84,16 +92,65 @@ public function table(Table $table): Table
->options(IncidentStatusEnum::class),
])
->headerActions([
Tables\Actions\CreateAction::make(),
Tables\Actions\CreateAction::make()
->action(function (CreateUpdateAction $createUpdate, array $data) {
/** @var Schedule|Incident $resource */
$resource = $this->getOwnerRecord();
$requestData = match (get_class($resource)) {
Schedule::class => CreateScheduleUpdateRequestData::from($data),
Incident::class => CreateIncidentUpdateRequestData::from($data),
default => throw new ErrorException('Request data resource mismatch')
};

$createUpdate->handle($resource, $requestData);

if($resource instanceof Incident) {
Notification::make()
->title(__('cachet::incident.record_update.success_title', ['name' => $resource->name]))
->body(__('cachet::incident.record_update.success_body'))
->success()
->send();

// Somehow the events aren't working to update the parent
// So then let's just refresh the page
redirect(request()->header('Referer'));
}
}),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
Tables\Actions\EditAction::make()
->after(function(SetLatestStatusIncident $latestStatusIncident) {
$this->afterChanged($latestStatusIncident);
}),
Tables\Actions\DeleteAction::make()
->after(function(SetLatestStatusIncident $latestStatusIncident) {
$this->afterChanged($latestStatusIncident);
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\DeleteBulkAction::make()->after(function(SetLatestStatusIncident $latestStatusIncident) {
$this->afterChanged($latestStatusIncident);
}),
]),
]);
}

protected function afterChanged(?SetLatestStatusIncident $latestStatusIncident = null): void
{
/** @var Schedule|Incident $resource */
$resource = $this->getOwnerRecord();
if(is_null($latestStatusIncident)) {
$latestStatusIncident = app()->make(SetLatestStatusIncident::class);
}

if ($resource instanceof Incident) {
$latestStatusIncident->handle($resource);

// Somehow the events aren't working to update the parent
// So then let's just refresh the page
redirect(request()->header('Referer'));
}

}
}
19 changes: 17 additions & 2 deletions src/Http/Controllers/Api/IncidentUpdateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Cachet\Http\Controllers\Api;

use Cachet\Actions\Incident\SetLatestStatusIncident;
use Cachet\Actions\Update\CreateUpdate;
use Cachet\Actions\Update\DeleteUpdate;
use Cachet\Actions\Update\EditUpdate;
Expand Down Expand Up @@ -79,23 +80,37 @@ public function show(Incident $incident, Update $update)
/**
* Update Incident Update
*/
public function update(EditIncidentUpdateRequestData $data, Incident $incident, Update $update, EditUpdate $editUpdateAction)
public function update(
EditIncidentUpdateRequestData $data,
Incident $incident,
Update $update,
EditUpdate $editUpdateAction,
SetLatestStatusIncident $latestStatusIncident,
)
{
$this->guard('incident-updates.manage');

$editUpdateAction->handle($update, $data);
$latestStatusIncident->handle($incident);


return UpdateResource::make($update->fresh());
}

/**
* Delete Incident Update
*/
public function destroy(Incident $incident, Update $update, DeleteUpdate $deleteUpdateAction)
public function destroy(
Incident $incident,
Update $update,
DeleteUpdate $deleteUpdateAction,
SetLatestStatusIncident $latestStatusIncident,
)
{
$this->guard('incident-updates.delete');

$deleteUpdateAction->handle($update);
$latestStatusIncident->handle($incident);

return response()->noContent();
}
Expand Down
48 changes: 45 additions & 3 deletions tests/Feature/Api/IncidentUpdateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@
it('can create an incident update', function () {
Sanctum::actingAs(User::factory()->create(), ['incident-updates.manage']);

$incident = Incident::factory()->create();
$incident = Incident::factory()->create([
'status' => IncidentStatusEnum::unknown->value,
]);

$response = postJson("/status/api/incidents/{$incident->id}/updates", [
'status' => IncidentStatusEnum::identified->value,
Expand All @@ -178,6 +180,9 @@
'status' => IncidentStatusEnum::identified->value,
'message' => 'This is a test message.',
]);
$this->assertDatabaseHas('incidents', [
'status' => IncidentStatusEnum::identified->value,
]);
});

it('cannot update an incident update if not authenticated', function () {
Expand Down Expand Up @@ -208,6 +213,7 @@
$incidentUpdate = Update::factory()->forIncident()->create();

$data = [
'status' => IncidentStatusEnum::fixed->value,
'message' => 'This is an updated message.',
];

Expand All @@ -216,9 +222,12 @@
$response->assertOk();
$this->assertDatabaseHas('updates', [
'id' => $incidentUpdate->id,
'status' => $incidentUpdate->status,
...$data,
]);
$this->assertDatabaseHas('incidents', [
'id' => $incidentUpdate->updateable->getKey(),
'status' => $data['status'],
]);
});

it('cannot delete an incident update if not authenticated', function () {
Expand All @@ -242,14 +251,47 @@
it('can delete an incident update', function () {
Sanctum::actingAs(User::factory()->create(), ['incident-updates.delete']);

$incidentUpdate = Update::factory()->forIncident()->create();
$incident = Incident::factory()->create(['status' => IncidentStatusEnum::watching->value]);
$incidentUpdateFirst = Update::factory()->forIncident($incident)->create([
'status' => IncidentStatusEnum::investigating
]);
$incidentUpdate = Update::factory()->forIncident($incident)->create([
'status' => IncidentStatusEnum::watching,
]);

$response = deleteJson("/status/api/incidents/{$incidentUpdate->updateable_id}/updates/{$incidentUpdate->id}");
$response->assertNoContent();
$this->assertDatabaseMissing('updates', [
'id' => $incidentUpdate->id,
'updateable_type' => Relation::getMorphAlias(Incident::class),
'updateable_id' => $incidentUpdate->updateable_id,
]);

$this->assertDatabaseHas('incidents', [
'id' => $incidentUpdateFirst->updateable_id,
'status' => $incidentUpdateFirst->status->value,
]);
});

it('can delete an incident first update', function () {
Sanctum::actingAs(User::factory()->create(), ['incident-updates.delete']);

$incident = Incident::factory()->create(['status' => IncidentStatusEnum::watching->value]);
$incidentUpdate = Update::factory()->forIncident($incident)->create([
'status' => IncidentStatusEnum::watching,
]);

$response = deleteJson("/status/api/incidents/{$incidentUpdate->updateable_id}/updates/{$incidentUpdate->id}");
$response->assertNoContent();
$this->assertDatabaseMissing('updates', [
'updateable_type' => Relation::getMorphAlias(Incident::class),
'updateable_id' => $incidentUpdate->updateable_id,
]);

$this->assertDatabaseHas('incidents', [
'id' => $incidentUpdate->updateable_id,
'status' => IncidentStatusEnum::unknown->value,
]);
});

it('cannot delete an incident update from another incident', function () {
Expand Down