Skip to content

Added plugin system for webhooks and removed discord webhooks - #2498

Open
JoanFo1456 wants to merge 5 commits into
pelican:mainfrom
JoanFo1456:webhooks
Open

Added plugin system for webhooks and removed discord webhooks#2498
JoanFo1456 wants to merge 5 commits into
pelican:mainfrom
JoanFo1456:webhooks

Conversation

@JoanFo1456

@JoanFo1456 JoanFo1456 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

This PR makes some changes that I think are necessary.
I removed discord webhooks to make them as a plugin myself so I can keep them Up to Date easier. Also thanks to this, people can make their own plugins of Webhooks, should be flexible for people and everything. Also allows adding new events.
Until this PR is merged I won't upload webhooks plugin, so if you need Discord Webhooks plugin to test this PR let me know on DM or somewhere.

PD: This PR was done with the help of AI, so if somewhere is really slop please let me know. Did it so we can just stop having problems with them...

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d3be306-eafb-4976-8128-33fec712e631

📥 Commits

Reviewing files that changed from the base of the PR and between 0a74f37 and 88cdb5b.

📒 Files selected for processing (4)
  • app/Extensions/Webhooks/Schemas/WebhookSchemaInterface.php
  • app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php
  • resources/views/filament/components/webhook-preview-section.blade.php
  • tests/Integration/Api/Application/WebhookControllerTest.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/Extensions/Webhooks/Schemas/WebhookSchemaInterface.php
  • resources/views/filament/components/webhook-preview-section.blade.php
  • tests/Integration/Api/Application/WebhookControllerTest.php

📝 Walkthrough

Walkthrough

The PR replaces the fixed webhook enum and Discord-specific paths with registered schemas. It adds shared forms and previews, application API endpoints, schema-driven validation and delivery, plugin availability handling, and integration coverage.

Changes

Webhook schema platform

Layer / File(s) Summary
Schema contracts and registration
app/Extensions/Webhooks/Schemas/*, app/Extensions/Webhooks/WebhookTypeService.php, app/Facades/WebhookTypes.php, app/Providers/Extensions/WebhookServiceProvider.php
Webhook schemas define metadata, forms, payload rules, request delivery, success handling, and retries. RegularSchema provides the built-in implementation.
Shared webhook forms and administration
app/Extensions/Webhooks/WebhookForm.php, app/Extensions/Webhooks/WebhookPreview.php, app/Filament/.../Webhooks/*, resources/views/filament/components/webhook-preview-section.blade.php
Admin and server forms use registered webhook types, schema-provided fields, generic previews, and schema mutation hooks.
Webhook application API
app/Http/Controllers/Api/Application/Webhooks/*, app/Http/Requests/Api/Application/Webhooks/*, app/Transformers/Api/Application/*Webhook*, routes/api-application.php
The application API supports webhook listing, retrieval, creation, updates, deletion, testing, type discovery, event discovery, validation, and permission checks.
Schema-aware delivery
app/Jobs/ProcessWebhook.php, app/Models/WebhookConfiguration.php, config/panel.php, tests/Integration/Webhooks/*
Delivery delegates payload preparation, headers, transport, success evaluation, and retry timing to the selected schema. Tests cover custom signing, transports, response handling, and payload rules.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: adding a webhook plugin system and removing built-in Discord webhooks.
Description check ✅ Passed The description directly explains the webhook plugin system, Discord webhook removal, custom plugins, and new event support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (3)
app/Extensions/Webhooks/WebhookTypeService.php (1)

18-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider surfacing duplicate type ids.

register() silently discards a schema when the id already exists. A plugin author gets no signal that the id clashed. Log a warning to make the conflict visible.

♻️ Proposed change
     public function register(WebhookSchemaInterface $schema): void
     {
         if (array_key_exists($schema->getId(), $this->schemas)) {
+            logger()->warning('Webhook type already registered, ignoring duplicate.', [
+                'type' => $schema->getId(),
+                'schema' => $schema::class,
+            ]);
+
             return;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Extensions/Webhooks/WebhookTypeService.php` around lines 18 - 25, Update
WebhookTypeService::register to log a warning when array_key_exists detects a
duplicate schema id before returning, including the conflicting id in the
warning; preserve the existing behavior of retaining the original schema and
skipping replacement.
app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php (1)

43-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Schema mutation hooks are copied across page classes. Each Filament webhook page repeats the same lookup of WebhookTypes::get($data['type'] ?? null) followed by a schema mutation call. The shared root cause is a missing trait for this hook.

  • app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php#L43-L59: move mutateFormDataBeforeSave and mutateFormDataBeforeFill into a new trait, for example MutatesWebhookFormData, and use the trait here.
  • app/Filament/Server/Resources/Webhooks/Pages/CreateWebhook.php#L47-L49: use the same trait and call its save-time helper after the server and scope assignments.

The admin create and edit pages contain the same block, so apply the trait there as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php` around lines 43
- 59, The webhook form-data mutation logic is duplicated across the server
pages. In app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php lines
43-59, move mutateFormDataBeforeSave and mutateFormDataBeforeFill into a shared
MutatesWebhookFormData trait and use it in EditWebhook; in
app/Filament/Server/Resources/Webhooks/Pages/CreateWebhook.php lines 47-49, use
the same trait and invoke its save-time mutation helper after server and scope
assignments. Apply the shared trait to the corresponding admin create and edit
pages as well.
app/Extensions/Webhooks/Schemas/BaseSchema.php (1)

122-125: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Cast the config value to int.

config('panel.webhook.timeout') resolves from env('APP_WEBHOOK_TIMEOUT', 30). Laravel returns environment values as strings, so this method returns a string that PHP coerces to int. If an operator sets a non-numeric value, the coercion raises a TypeError inside the queued job. An explicit cast removes that failure mode.

♻️ Proposed change
     protected function getTimeout(): int
     {
-        return config('panel.webhook.timeout', 30);
+        return (int) config('panel.webhook.timeout', 30);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Extensions/Webhooks/Schemas/BaseSchema.php` around lines 122 - 125,
Update the getTimeout() method to explicitly cast the panel.webhook.timeout
configuration value to int before returning it, while retaining the existing 30
default.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Extensions/Webhooks/WebhookForm.php`:
- Around line 19-29: Update typeSelector() so stored webhook types that are no
longer returned by WebhookTypes::getOptions() remain valid during editing:
include the current record’s unavailable type as a disabled option, or
conditionally relax ToggleButtons’ implicit option validation for that record,
while preserving unavailable_type display behavior.

In `@app/Extensions/Webhooks/WebhookPreview.php`:
- Around line 48-52: Update WebhookPreview to accept and use a resolved scope
property when building sample data, falling back to the record scope only when
appropriate so server create previews select getServerWebhookSampleData(). Pass
the section’s resolved scope into the component when it mounts from
webhook-preview-section.blade.php, preserving existing behavior for global
previews and saved records.

In `@app/Filament/Admin/Resources/Webhooks/WebhookResource.php`:
- Line 177: Update the endpoint field’s afterStateUpdated callback to read the
current type and apply WebhookTypeService::detect($state) only when the type is
empty or equals WebhookTypeService::Default; otherwise preserve the user’s
explicit selection. Import and use App\Extensions\Webhooks\WebhookTypeService.

In `@app/Filament/Server/Resources/Webhooks/WebhookResource.php`:
- Around line 133-135: Update the endpoint TextInput in WebhookResource to reuse
the existing shared endpoint validation rule if one exists, ensuring URL
validation restricts accepted schemes to HTTP/HTTPS as appropriate. Preserve the
required constraint and align the server panel form validation with the API
request classes.
- Line 136: Update the endpoint after-state handler in WebhookResource so it
only assigns the detected type when WebhookTypes::detect($state) identifies a
schema or when the current type is empty; otherwise preserve the manually
selected or existing type, including legacy plugin types. Use the current form
state to avoid overwriting it with the detector’s regular fallback.

In `@app/Http/Requests/Api/Application/Webhooks/GetWebhookRequest.php`:
- Around line 9-14: Add validation rules to GetWebhookRequest so per_page is a
positive, bounded integer and scope accepts only WebhookScope::global or
WebhookScope::server. Ensure index() and events() consume the validated values,
preventing invalid scope values from defaulting to WebhookScope::Global.

In `@app/Http/Requests/Api/Application/Webhooks/StoreWebhookRequest.php`:
- Around line 47-53: Guard dynamic request inputs in StoreWebhookRequest,
including resolveType and the rules()/withValidator() resolver paths, so array
values for type, endpoint, or scope are rejected or normalized to a single
string before calling WebhookTypes::get(), WebhookTypes::detect(), or
WebhookScope::tryFrom(). Preserve valid scalar inputs and ensure malformed
arrays produce normal validation errors; the inherited UpdateWebhookRequest
behavior must receive the same protection.

In `@app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php`:
- Around line 42-45: Update hasServer() to detect whether server_id was
explicitly supplied, including null, and avoid falling back to
record()->server_id in that case; only use the stored server ID when the field
is omitted, so an explicit null is rejected for server-scoped webhooks.
- Around line 18-25: Update the validation logic in UpdateWebhookRequest::rules
so required rules for schema payload fields are relaxed when PATCH omits
payload, while preserving full payload validation whenever payload is present.
Do not broadly convert required rules for unrelated fields such as name,
endpoint, or events; target the payload validation rules specifically. Add a
regression test using a schema with a required payload field and a PATCH that
changes only another attribute.
- Around line 33-57: Update the PATCH handling around resolveScope(),
resolveType(), and persistence so inferred scope is stored when server_id is
provided without scope, and inferred type is stored when endpoint is provided
without type. Merge these resolved values into the validated attributes before
saving, preserving explicitly supplied scope and type values and keeping
validation, event selection, and delivery consistent.

In `@app/Jobs/ProcessWebhook.php`:
- Around line 59-60: Update the failure reporting in ProcessWebhook so it no
longer includes the full webhookConfiguration->endpoint. Report the webhook
configuration ID together with a redacted host or URL, ensuring credentials and
bearer tokens cannot reach logs or error reporting.

In `@app/Transformers/Api/Application/WebhookConfigurationTransformer.php`:
- Around line 71-79: Replace the unbounded includeDeliveries implementation with
a bounded, paginated webhook-deliveries endpoint or a documented relation that
returns only recent deliveries. Ensure the query excludes soft-deleted rows and
applies explicit ordering and limits, rather than loading the full webhooks
history through getRelation('webhooks'); update the surrounding transformer/API
wiring to use that bounded source.

In `@resources/views/filament/components/webhook-preview-section.blade.php`:
- Around line 76-81: Update the preview payload construction in the foreach over
$previewFields to resolve dotted field names as nested paths within formData,
rather than accessing them as literal top-level keys. Preserve null fallback for
missing values and continue dispatching the resolved payload through
webhook-form-changed.

---

Nitpick comments:
In `@app/Extensions/Webhooks/Schemas/BaseSchema.php`:
- Around line 122-125: Update the getTimeout() method to explicitly cast the
panel.webhook.timeout configuration value to int before returning it, while
retaining the existing 30 default.

In `@app/Extensions/Webhooks/WebhookTypeService.php`:
- Around line 18-25: Update WebhookTypeService::register to log a warning when
array_key_exists detects a duplicate schema id before returning, including the
conflicting id in the warning; preserve the existing behavior of retaining the
original schema and skipping replacement.

In `@app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php`:
- Around line 43-59: The webhook form-data mutation logic is duplicated across
the server pages. In
app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php lines 43-59, move
mutateFormDataBeforeSave and mutateFormDataBeforeFill into a shared
MutatesWebhookFormData trait and use it in EditWebhook; in
app/Filament/Server/Resources/Webhooks/Pages/CreateWebhook.php lines 47-49, use
the same trait and invoke its save-time mutation helper after server and scope
assignments. Apply the shared trait to the corresponding admin create and edit
pages as well.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f7e06f1d-74a0-45dc-9940-da85fb7d2820

📥 Commits

Reviewing files that changed from the base of the PR and between 4722aea and a4200ad.

📒 Files selected for processing (40)
  • app/Enums/WebhookType.php
  • app/Extensions/Webhooks/Schemas/BaseSchema.php
  • app/Extensions/Webhooks/Schemas/RegularSchema.php
  • app/Extensions/Webhooks/Schemas/WebhookSchemaInterface.php
  • app/Extensions/Webhooks/WebhookForm.php
  • app/Extensions/Webhooks/WebhookPreview.php
  • app/Extensions/Webhooks/WebhookTypeService.php
  • app/Facades/WebhookTypes.php
  • app/Filament/Admin/Resources/Webhooks/Pages/CreateWebhookConfiguration.php
  • app/Filament/Admin/Resources/Webhooks/Pages/EditWebhookConfiguration.php
  • app/Filament/Admin/Resources/Webhooks/WebhookResource.php
  • app/Filament/Server/Resources/Webhooks/Pages/CreateWebhook.php
  • app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php
  • app/Filament/Server/Resources/Webhooks/WebhookResource.php
  • app/Http/Controllers/Api/Application/Webhooks/WebhookController.php
  • app/Http/Requests/Api/Application/Webhooks/DeleteWebhookRequest.php
  • app/Http/Requests/Api/Application/Webhooks/GetWebhookRequest.php
  • app/Http/Requests/Api/Application/Webhooks/StoreWebhookRequest.php
  • app/Http/Requests/Api/Application/Webhooks/TestWebhookRequest.php
  • app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php
  • app/Jobs/ProcessWebhook.php
  • app/Livewire/DiscordPreview.php
  • app/Models/ApiKey.php
  • app/Models/WebhookConfiguration.php
  • app/Providers/Extensions/WebhookServiceProvider.php
  • app/Providers/Filament/FilamentServiceProvider.php
  • app/Transformers/Api/Application/WebhookConfigurationTransformer.php
  • app/Transformers/Api/Application/WebhookDeliveryTransformer.php
  • bootstrap/providers.php
  • config/panel.php
  • database/Factories/WebhookConfigurationFactory.php
  • database/migrations/2025_04_09_015500_add_webhook_configurations_type_column.php
  • lang/en/admin/webhook.php
  • resources/css/discord-preview.css
  • resources/views/filament/components/webhook-preview-section.blade.php
  • resources/views/livewire/discord-preview.blade.php
  • routes/api-application.php
  • tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php
  • tests/Integration/Api/Application/WebhookControllerTest.php
  • tests/Integration/Webhooks/WebhookSchemaExtensionTest.php
💤 Files with no reviewable changes (5)
  • app/Providers/Filament/FilamentServiceProvider.php
  • resources/views/livewire/discord-preview.blade.php
  • app/Livewire/DiscordPreview.php
  • resources/css/discord-preview.css
  • app/Enums/WebhookType.php

Comment thread app/Extensions/Webhooks/WebhookForm.php
Comment thread app/Extensions/Webhooks/WebhookPreview.php
Comment thread app/Filament/Admin/Resources/Webhooks/WebhookResource.php Outdated
Comment thread app/Filament/Server/Resources/Webhooks/WebhookResource.php
Comment thread app/Filament/Server/Resources/Webhooks/WebhookResource.php Outdated
Comment thread app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php Outdated
Comment thread app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php
Comment thread app/Jobs/ProcessWebhook.php Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php`:
- Around line 37-39: Update
app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php at lines
37-39, 47-57, and 93-103 to construct the effective webhook configuration from
stored values plus validated request data before persisting changes: apply
payload rules when the effective type changes even if payload is omitted,
validate retained stored events when the effective scope changes, and save
discriminator changes only after effective-state validation succeeds. Add
regression coverage in
tests/Integration/Api/Application/WebhookControllerTest.php lines 195-264 for
changing to a required-payload type without payload and changing to server scope
while retaining global-only events.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ffbdf4dc-f7bb-46b0-929b-c07989debd05

📥 Commits

Reviewing files that changed from the base of the PR and between a4200ad and 0a74f37.

📒 Files selected for processing (21)
  • app/Extensions/Webhooks/Schemas/BaseSchema.php
  • app/Extensions/Webhooks/WebhookForm.php
  • app/Extensions/Webhooks/WebhookPreview.php
  • app/Extensions/Webhooks/WebhookTypeService.php
  • app/Facades/WebhookTypes.php
  • app/Filament/Admin/Resources/Webhooks/Pages/CreateWebhookConfiguration.php
  • app/Filament/Admin/Resources/Webhooks/Pages/EditWebhookConfiguration.php
  • app/Filament/Admin/Resources/Webhooks/WebhookResource.php
  • app/Filament/Server/Resources/Webhooks/Pages/CreateWebhook.php
  • app/Filament/Server/Resources/Webhooks/Pages/EditWebhook.php
  • app/Filament/Server/Resources/Webhooks/WebhookResource.php
  • app/Http/Controllers/Api/Application/Webhooks/WebhookController.php
  • app/Http/Requests/Api/Application/Webhooks/GetWebhookRequest.php
  • app/Http/Requests/Api/Application/Webhooks/StoreWebhookRequest.php
  • app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php
  • app/Jobs/ProcessWebhook.php
  • app/Traits/Filament/MutatesWebhookFormData.php
  • app/Transformers/Api/Application/WebhookConfigurationTransformer.php
  • lang/en/admin/webhook.php
  • resources/views/filament/components/webhook-preview-section.blade.php
  • tests/Integration/Api/Application/WebhookControllerTest.php
🚧 Files skipped from review as they are similar to previous changes (11)
  • resources/views/filament/components/webhook-preview-section.blade.php
  • app/Facades/WebhookTypes.php
  • app/Transformers/Api/Application/WebhookConfigurationTransformer.php
  • app/Filament/Server/Resources/Webhooks/WebhookResource.php
  • app/Filament/Admin/Resources/Webhooks/Pages/EditWebhookConfiguration.php
  • lang/en/admin/webhook.php
  • app/Extensions/Webhooks/Schemas/BaseSchema.php
  • app/Http/Controllers/Api/Application/Webhooks/WebhookController.php
  • app/Jobs/ProcessWebhook.php
  • app/Filament/Admin/Resources/Webhooks/Pages/CreateWebhookConfiguration.php
  • app/Extensions/Webhooks/WebhookForm.php

Comment thread app/Http/Requests/Api/Application/Webhooks/UpdateWebhookRequest.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant