*/ public static function events(): array { $changes = []; foreach (self::RESOURCES as $resource) { foreach (self::ACTIONS as $action) { $changes[] = "{$resource}.{$action}"; } } return [...self::EVENTS, ...$changes]; } /** * What a webhook may subscribe to: an event, `*`, everything about one * kind of record (`projects.*`) or one action on any (`*.deleted`). */ public static function isSubscribable(string $pattern): bool { if ($pattern === '*' || in_array($pattern, self::events(), true)) { return true; } [$resource, $action] = array_pad(explode('.', $pattern, 2), 2, null); return ($action === '*' && in_array($resource, self::RESOURCES, true)) || ($resource === '*' && in_array($action, self::ACTIONS, true)); } /** * Switched off after this many failed deliveries in a row, so a dead * endpoint does not keep a queue busy forever. Switching it back on is a * person's decision. */ public const MAX_FAILURES = 20; protected $attributes = [ 'include_personal_data' => false, 'is_active' => true, ]; protected function casts(): array { return [ 'secret' => 'encrypted', 'events' => 'array', 'include_personal_data' => 'boolean', 'is_active' => 'boolean', 'last_delivered_at' => 'datetime', ]; } /** * @return HasMany */ public function deliveries(): HasMany { return $this->hasMany(WebhookDelivery::class)->latest('id'); } public function listensTo(string $event): bool { foreach ($this->events ?? [] as $pattern) { if ($pattern === $event || Str::is($pattern, $event)) { return true; } } return false; } /** * @param Builder<$this> $query * @return Builder<$this> */ public function scopeActive(Builder $query): Builder { return $query->where('is_active', true); } }