$data * @param array $personal Sent only to webhooks that opted into personal data. */ public static function dispatch(string $event, array $data, array $personal = []): void { $webhooks = Webhook::query()->active()->get()->filter(fn (Webhook $w) => $w->listensTo($event)); foreach ($webhooks as $webhook) { $delivery = $webhook->deliveries()->create([ 'uuid' => (string) Str::uuid(), 'event' => $event, 'payload' => $webhook->include_personal_data ? [...$data, ...$personal] : $data, ]); DeliverWebhook::dispatch($delivery)->afterCommit(); } } /** * A `ping`, to check the receiving end before anything real happens. */ public static function ping(Webhook $webhook): WebhookDelivery { $delivery = $webhook->deliveries()->create([ 'uuid' => (string) Str::uuid(), 'event' => 'ping', 'payload' => ['webhook' => $webhook->id, 'events' => $webhook->events], ]); DeliverWebhook::dispatch($delivery); return $delivery->refresh(); } /** * One sent again, as a new delivery of the same event and payload. */ public static function redeliver(WebhookDelivery $delivery): WebhookDelivery { $again = $delivery->webhook->deliveries()->create([ 'uuid' => (string) Str::uuid(), 'event' => $delivery->event, 'payload' => $delivery->payload, ]); DeliverWebhook::dispatch($again); return $again->refresh(); } public static function applicationReceived(Application $application): void { self::dispatch('application.received', [ 'id' => $application->id, 'kind' => $application->kind->value, 'call_id' => $application->call_id, 'subject' => $application->subject(), 'locale' => $application->locale, 'created_at' => $application->created_at?->toIso8601String(), ], [ 'name' => $application->name, 'email' => $application->email, 'organisation' => $application->organisation, 'message' => $application->message, ]); } /** * Publishing and unpublishing are already told apart by the history, for * every kind of record and from wherever it happened; this listens there. */ public static function revisionRecorded(Revision $revision): void { $model = Relation::getMorphedModel($revision->revisionable_type) ?? $revision->revisionable_type; $record = $model::query()->find($revision->revisionable_id); if ($record === null) { return; } $event = match (true) { $revision->event === 'published' => 'content.published', $revision->event === 'unpublished' => 'content.unpublished', $revision->event === 'created' && method_exists($record, 'isPublishedNow') && $record->isPublishedNow() => 'content.published', default => null, }; if ($event !== null) { self::dispatch($event, self::describe($record)); } } public static function reviewRecorded(ReviewComment $comment): void { $event = match ($comment->event->value) { 'requested' => 'review.requested', 'returned' => 'review.returned', default => null, }; $record = $comment->reviewable; if ($event === null || $record === null) { return; } self::dispatch($event, [ ...self::describe($record), 'by' => $comment->user_name, 'note' => $comment->body, ]); } /** * @return array */ protected static function describe(Model $record): array { $type = AdminContent::nameOf($record); $siteType = AdminContent::PREVIEWABLE[$type] ?? null; $locale = (string) config('locales.default'); return [ 'type' => $type, 'id' => $record->getKey(), 'title' => ContentTypes::title($record), 'url' => $siteType && method_exists($record, 'getTranslation') ? (SiteUrls::absoluteAlternates($record, $siteType)[$locale] ?? null) : null, ]; } }