-
-
Notifications
You must be signed in to change notification settings - Fork 60
feat: Webhooks #165
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
Merged
Merged
feat: Webhooks #165
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
d869426
chore: install Spatie webhooks server
danjohnson95 edbd3c4
chore: create migration for subscriptions table
danjohnson95 2b15b07
chore: create enum for all events
danjohnson95 520b476
chore: create model for subscription
danjohnson95 eef30dc
chore: create WebhookAttempt
danjohnson95 d74a78f
chore: add relation from webhook subscription to attempts
danjohnson95 9d6507a
feat: add config variable for when webhook logs are pruned
danjohnson95 1db4ab3
feat: create the SendsWebhook concern
danjohnson95 6ed8f7c
feat: create class for dispatching webhooks
danjohnson95 d322dbb
feat: include event name in webhook payload
danjohnson95 9d467a0
feat: create listener to dispatch webhook for events that use SendsWe…
danjohnson95 285a055
chore: register event for sending webhooks
danjohnson95 c0291c1
feat: create and register listener for creating a Webhook Attempt
danjohnson95 31d1788
feat: create views for managing webhooks
danjohnson95 f45016d
chore: add language strings for webhooks
danjohnson95 1c8c925
chore: remove unused strings
danjohnson95 c28ea88
feat: hook up events with webhooks
danjohnson95 bf1aec0
chore: create factories
danjohnson95 7935dbd
test: create test for webhook subscription model
danjohnson95 8e3de1e
test: create test for SendWebhookListener
danjohnson95 49f9239
chore: make secret hidden
danjohnson95 575591d
feat: include success rate
danjohnson95 bfd6ec4
chore: phpstan fixes
danjohnson95 d639e30
feat: add ability to confgure webhook queue connection and name
danjohnson95 ef027a9
feat: wrap helper text in link
danjohnson95 bceb6e4
refact: create TextWithLink Htmlable class
danjohnson95 e6ecbb6
chore: remove unused import
danjohnson95 15e054b
chore: full width settings for editing webhooks
danjohnson95 4f6da89
fix: satisfy phpstan with new self in place of new static
danjohnson95 23f2f82
feat: use full width on creation, then split for edit
danjohnson95 199cedb
feat: put attempts underneath buttons
danjohnson95 449b358
feat: support updating secret from action button
danjohnson95 2b29ad2
Fix tests
jbrooksuk 1377795
Make the secret a revealable password field
jbrooksuk cf2d85b
fix: use correct Action class
danjohnson95 e99e3a2
Merge branch '106-webhooks' of github.com:danjohnson95/cachet-core in…
danjohnson95 a08dbea
Set user agent for webhooks
jbrooksuk 909fb2d
Merge branch 'main' of https://github.com/cachethq/core into 106-webh…
danjohnson95 31681a0
Merge branch '106-webhooks' of github.com:danjohnson95/cachet-core in…
danjohnson95 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Cachet\Database\Factories; | ||
|
||
use Cachet\Enums\WebhookEventEnum; | ||
use Cachet\Models\WebhookAttempt; | ||
use Cachet\Models\WebhookSubscription; | ||
use Illuminate\Database\Eloquent\Factories\Factory; | ||
|
||
/** | ||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\Cachet\Models\WebhookAttempt> | ||
*/ | ||
class WebhookAttemptFactory extends Factory | ||
{ | ||
protected $model = WebhookAttempt::class; | ||
|
||
/** | ||
* Define the model's default state. | ||
* | ||
* @return array<string, mixed> | ||
*/ | ||
public function definition(): array | ||
{ | ||
return [ | ||
'subscription_id' => WebhookSubscription::factory(), | ||
'event' => WebhookEventEnum::component_created, | ||
'attempt' => 0, | ||
'payload' => [], | ||
'response_code' => 200, | ||
'transfer_time' => 0.1, | ||
]; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
namespace Cachet\Database\Factories; | ||
|
||
use Cachet\Models\WebhookSubscription; | ||
use Illuminate\Database\Eloquent\Factories\Factory; | ||
|
||
/** | ||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\Cachet\Models\WebhookSubscription> | ||
*/ | ||
class WebhookSubscriptionFactory extends Factory | ||
{ | ||
protected $model = WebhookSubscription::class; | ||
|
||
/** | ||
* Define the model's default state. | ||
* | ||
* @return array<string, mixed> | ||
*/ | ||
public function definition(): array | ||
{ | ||
return [ | ||
'url' => fake()->url, | ||
'secret' => fake()->randomAscii(), | ||
'description' => fake()->sentence(), | ||
'send_all_events' => false, | ||
'selected_events' => [], | ||
]; | ||
} | ||
|
||
/** | ||
* Create a webhook subscription that is enabled for all events | ||
*/ | ||
public function allEvents(): self | ||
{ | ||
return $this->state([ | ||
'send_all_events' => true, | ||
]); | ||
} | ||
|
||
/** | ||
* Create a webhook subscription that is only enabled | ||
* for the given events. | ||
*/ | ||
public function selectedEvents(array $events): self | ||
{ | ||
return $this->state([ | ||
'selected_events' => $events, | ||
]); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
database/migrations/2025_01_02_193833_create_webhook_subscriptions_table.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
use Illuminate\Database\Migrations\Migration; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Support\Facades\Schema; | ||
|
||
return new class extends Migration | ||
{ | ||
/** | ||
* Run the migrations. | ||
*/ | ||
public function up(): void | ||
{ | ||
Schema::create('webhook_subscriptions', function (Blueprint $table) { | ||
$table->id(); | ||
$table->string('url'); | ||
$table->string('secret'); | ||
$table->string('description')->nullable(); | ||
$table->boolean('send_all_events')->default(true); | ||
$table->json('selected_events')->nullable(); | ||
$table->decimal('success_rate_24h', 5, 2)->nullable(); | ||
|
||
$table->timestamps(); | ||
}); | ||
} | ||
|
||
/** | ||
* Reverse the migrations. | ||
*/ | ||
public function down(): void | ||
{ | ||
Schema::dropIfExists('webhook_subscriptions'); | ||
} | ||
}; |
34 changes: 34 additions & 0 deletions
34
database/migrations/2025_01_03_144743_create_webhook_attempts_table.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
use Cachet\Models\WebhookSubscription; | ||
use Illuminate\Database\Migrations\Migration; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Support\Facades\Schema; | ||
|
||
return new class extends Migration | ||
{ | ||
/** | ||
* Run the migrations. | ||
*/ | ||
public function up(): void | ||
{ | ||
Schema::create('webhook_attempts', function (Blueprint $table) { | ||
$table->id(); | ||
$table->foreignIdFor(WebhookSubscription::class, 'subscription_id')->onDelete('cascade'); | ||
$table->string('event'); | ||
$table->unsignedTinyInteger('attempt'); | ||
$table->json('payload'); | ||
$table->unsignedSmallInteger('response_code')->nullable(); | ||
$table->unsignedTinyInteger('transfer_time')->nullable(); | ||
$table->timestamps(); | ||
}); | ||
} | ||
|
||
/** | ||
* Reverse the migrations. | ||
*/ | ||
public function down(): void | ||
{ | ||
Schema::drop('webhook_attempts'); | ||
} | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
return [ | ||
'resource_label' => 'Webhook|Webhooks', | ||
'event_selection' => [ | ||
'all' => 'Send all events', | ||
'selected' => 'Only send selected events', | ||
], | ||
'form' => [ | ||
'url_label' => 'Payload URL', | ||
'url_helper' => 'Events will POST to this URL.', | ||
'secret_label' => 'Secret', | ||
'secret_helper' => 'The payload will be signed with this secret. See *webhook documentation* for more information.', | ||
'description_label' => 'Description', | ||
'event_selection_label' => 'Send all events?', | ||
'events_label' => 'Events', | ||
'edit_secret_label' => 'Edit secret', | ||
'update_secret_label' => 'Update secret', | ||
], | ||
'attempts' => [ | ||
'heading' => 'Attempts', | ||
'empty_state' => 'No attempts have been made to this webhook yet', | ||
], | ||
'list' => [ | ||
'headers' => [ | ||
'url' => 'Payload URL', | ||
'success_rate_24h' => 'Success rate (24h)', | ||
], | ||
], | ||
]; |
14 changes: 14 additions & 0 deletions
14
resources/views/filament/pages/settings/edit-webhook-subscription.blade.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<x-filament-panels::page> | ||
<x-filament-panels::form wire:submit="save"> | ||
{{ $this->form }} | ||
|
||
<x-filament-panels::form.actions | ||
:actions="$this->getCachedFormActions()" | ||
:full-width="$this->hasFullWidthFormActions()" | ||
/> | ||
</x-filament-panels::form> | ||
|
||
{{ view('cachet::filament.widgets.webhook-attempts', [ | ||
'attempts' => $this->record->attempts, | ||
]) }} | ||
</x-filament-panels::page> |
24 changes: 24 additions & 0 deletions
24
resources/views/filament/widgets/webhook-attempts.blade.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<x-filament::section heading="{{ __('cachet::webhook.attempts.heading') }}"> | ||
<div class="space-y-4 text-sm"> | ||
@forelse($attempts as $attempt) | ||
<div class="flex items-center space-x-2"> | ||
<div @class([ | ||
'bg-red-100 text-red-500' => !$attempt->isSuccess(), | ||
'bg-primary-100 text-primary-500' => $attempt->isSuccess(), | ||
'flex-shrink-0 whitespace-nowrap px-1 py-1 rounded-md font-semibold' => true, | ||
])> | ||
@if ($attempt->isSuccess()) | ||
<x-heroicon-m-check class="size-5" /> | ||
@else | ||
<x-heroicon-m-x-mark class="size-5" /> | ||
@endif | ||
</div> | ||
|
||
<div class="font-mono font-medium flex-1">{{ $attempt->event }}</div> | ||
<div class="text-gray-500 flex-shrink-0">{{ $attempt->created_at?->toDateTimeString() }}</div> | ||
</div> | ||
@empty | ||
<div class="text-gray-500">{{ __('cachet::webhook.attempts.empty_state') }}</div> | ||
@endforelse | ||
</div> | ||
</x-filament::section> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Cachet\Actions\Webhook; | ||
|
||
use Cachet\Enums\WebhookEventEnum; | ||
use Cachet\Models\WebhookSubscription; | ||
use Illuminate\Database\Eloquent\Collection; | ||
|
||
class DispatchWebhooks | ||
{ | ||
protected mixed $event; | ||
protected WebhookEventEnum $eventName; | ||
|
||
public function handle(mixed $event): void | ||
{ | ||
$this->event = $event; | ||
$this->eventName = $this->event->getWebhookEventName(); | ||
|
||
$payload = $this->event->getWebhookPayload(); | ||
|
||
foreach ($this->getWebhookSubscriptionsForEvent() as $webhookSubscription) { | ||
$webhookSubscription->makeCall($this->eventName, $payload)->dispatch(); | ||
} | ||
} | ||
|
||
/** | ||
* @return Collection<WebhookSubscription> | ||
*/ | ||
private function getWebhookSubscriptionsForEvent(): Collection | ||
{ | ||
return WebhookSubscription::whereEvent($this->eventName)->get(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
namespace Cachet\Concerns; | ||
|
||
use Cachet\Enums\WebhookEventEnum; | ||
use Exception; | ||
|
||
trait SendsWebhook | ||
{ | ||
public function getWebhookPayload(): array | ||
{ | ||
return []; | ||
} | ||
|
||
public function getWebhookEventName(): WebhookEventEnum | ||
{ | ||
throw new Exception('You must implement the getWebhookEventName method on ' . static::class); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace Cachet\Enums; | ||
|
||
enum WebhookEventEnum: string | ||
{ | ||
case component_created = 'component_created'; | ||
case component_updated = 'component_updated'; | ||
case component_deleted = 'component_deleted'; | ||
case component_status_changed = 'component_status_changed'; | ||
|
||
case incident_created = 'incident_created'; | ||
case incident_updated = 'incident_updated'; | ||
case incident_deleted = 'incident_deleted'; | ||
|
||
case metric_created = 'metric_created'; | ||
case metric_updated = 'metric_updated'; | ||
case metric_deleted = 'metric_deleted'; | ||
case metric_point_created = 'metric_point_created'; | ||
case metric_point_deleted = 'metric_point_deleted'; | ||
|
||
case subscriber_created = 'subscriber_created'; | ||
case subscriber_unsubscribed = 'subscriber_unsubscribed'; | ||
case subscriber_verified = 'subscriber_verified'; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.