use BookStack\Auth\User;
use BookStack\Entities\Models\Entity;
+use BookStack\Facades\Theme;
use BookStack\Interfaces\Loggable;
use BookStack\Model;
+use BookStack\Theming\ThemeEvents;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
*/
public function handle()
{
+ $themeResponse = Theme::dispatch(ThemeEvents::WEBHOOK_CALL_BEFORE, $this->event, $this->webhook, $this->detail);
+ $webhookData = $themeResponse ?? $this->buildWebhookData();
+
$response = Http::asJson()
->withOptions(['allow_redirects' => ['strict' => true]])
->timeout(3)
- ->post($this->webhook->endpoint, $this->buildWebhookData());
+ ->post($this->webhook->endpoint, $webhookData);
if ($response->failed()) {
Log::error("Webhook call to endpoint {$this->webhook->endpoint} failed with status {$response->status()}");
* @returns \League\CommonMark\ConfigurableEnvironmentInterface|null
*/
const COMMONMARK_ENVIRONMENT_CONFIGURE = 'commonmark_environment_configure';
+
+ /**
+ * Webhook call before event.
+ * Runs before a webhook endpoint is called. Allows for customization
+ * of the data format & content within the webhook POST request.
+ * Provides the original event name as a string (see \BookStack\Actions\ActivityType)
+ * along with the webhook instance along with the event detail which may be a
+ * "Loggable" model type or a string.
+ * If the listener returns a non-null value, that will be used as the POST data instead
+ * of the system default.
+ *
+ * @param string $event
+ * @param \BookStack\Actions\Webhook $webhook
+ * @param string|\BookStack\Interfaces\Loggable $detail
+ */
+ const WEBHOOK_CALL_BEFORE = 'webhook_call_before';
}
namespace Tests;
+use BookStack\Actions\ActivityType;
+use BookStack\Actions\DispatchWebhookJob;
+use BookStack\Actions\Webhook;
use BookStack\Auth\User;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Tools\PageContent;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use Illuminate\Console\Command;
+use Illuminate\Http\Client\Request as HttpClientRequest;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
+use Illuminate\Support\Facades\Http;
use League\CommonMark\ConfigurableEnvironmentInterface;
class ThemeTest extends TestCase
$this->assertInstanceOf(User::class, $args[1]);
}
+ public function test_event_webhook_call_before()
+ {
+ $args = [];
+ $callback = function (...$eventArgs) use (&$args) {
+ $args = $eventArgs;
+ return ['test' => 'hello!'];
+ };
+ Theme::listen(ThemeEvents::WEBHOOK_CALL_BEFORE, $callback);
+
+ Http::fake([
+ '*' => Http::response('', 200),
+ ]);
+
+ $webhook = new Webhook(['name' => 'Test webhook', 'endpoint' => 'https://example.com']);
+ $webhook->save();
+ $event = ActivityType::PAGE_UPDATE;
+ $detail = Page::query()->first();
+
+ dispatch((new DispatchWebhookJob($webhook, $event, $detail)));
+
+ $this->assertCount(3, $args);
+ $this->assertEquals($event, $args[0]);
+ $this->assertEquals($webhook->id, $args[1]->id);
+ $this->assertEquals($detail->id, $args[2]->id);
+
+ Http::assertSent(function (HttpClientRequest $request) {
+ return $request->isJson() && $request->data()['test'] === 'hello!';
+ });
+ }
+
public function test_add_social_driver()
{
Theme::addSocialDriver('catnet', [