diff --git a/app/Models/WebhookConfiguration.php b/app/Models/WebhookConfiguration.php index cf792da195..309565bc62 100644 --- a/app/Models/WebhookConfiguration.php +++ b/app/Models/WebhookConfiguration.php @@ -34,6 +34,24 @@ class WebhookConfiguration extends Model 'events', ]; + public static function getEventClassesFromDirectory(string $directory, string $after): array + { + $events = []; + foreach (File::allFiles($directory) as $file) { + $namespace = str($file->getPath()) + ->after($after) + ->replace(DIRECTORY_SEPARATOR, '\\') + ->after('\\') + ->replaceFirst('app', 'App') + ->toString(); + + $events[] = $namespace.'\\'.str($file->getFilename()) + ->replace([DIRECTORY_SEPARATOR, '.php'], ['\\', '']); + } + + return $events; + } + protected function casts(): array { return [ @@ -75,6 +93,7 @@ public static function allPossibleEvents(): array { return collect(static::discoverCustomEvents()) ->merge(static::allModelEvents()) + ->merge(static::discoverFrameworkEvents()) ->unique() ->filter(fn ($event) => !in_array($event, static::$eventBlacklist)) ->all(); @@ -97,6 +116,7 @@ public static function transformClassName(string $event): string ->after('eloquent.') ->replace('App\\Models\\', '') ->replace('App\\Events\\', 'event: ') + ->replaceMatches('/Illuminate\\\\([A-z]+)\\\\Events\\\\/', fn (array $matches) => strtolower($matches[1]) . ': ') ->toString(); } @@ -133,16 +153,23 @@ public static function discoverCustomEvents(): array { $directory = app_path('Events'); + return self::getEventClassesFromDirectory($directory, base_path()); + } + + public static function discoverFrameworkEvents(): array + { + $frameworkDirectory = 'vendor/laravel/framework/src/'; + + $eventDirectories = [ + 'Illuminate/Auth/Events', + 'Illuminate/Queue/Events', + ]; + $events = []; - foreach (File::allFiles($directory) as $file) { - $namespace = str($file->getPath()) - ->after(base_path()) - ->replace(DIRECTORY_SEPARATOR, '\\') - ->replace('\\app\\', 'App\\') - ->toString(); + foreach ($eventDirectories as $eventDirectory) { + $directory = base_path("$frameworkDirectory/$eventDirectory"); - $events[] = $namespace . '\\' . str($file->getFilename()) - ->replace([DIRECTORY_SEPARATOR, '.php'], ['\\', '']); + $events = array_merge($events, static::getEventClassesFromDirectory($directory, $frameworkDirectory)); } return $events; diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 50a6e42cdd..284718d70c 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -15,5 +15,7 @@ class EventServiceProvider extends ServiceProvider 'eloquent.created*' => [DispatchWebhooks::class], 'eloquent.deleted*' => [DispatchWebhooks::class], 'eloquent.updated*' => [DispatchWebhooks::class], + 'Illuminate\\Auth\\Events\\*' => [DispatchWebhooks::class], + 'Illuminate\\Queue\\Events\\*' => [DispatchWebhooks::class], ]; } diff --git a/tests/Feature/Webhooks/DispatchWebhooksTest.php b/tests/Feature/Webhooks/DispatchWebhooksTest.php index 7fcb1e326d..89b89f99c6 100644 --- a/tests/Feature/Webhooks/DispatchWebhooksTest.php +++ b/tests/Feature/Webhooks/DispatchWebhooksTest.php @@ -4,9 +4,12 @@ use App\Jobs\ProcessWebhook; use App\Models\Server; +use App\Models\User; use App\Models\WebhookConfiguration; use App\Tests\TestCase; +use Illuminate\Auth\Events\Authenticated; use Illuminate\Foundation\Testing\LazilyRefreshDatabase; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Queue; class DispatchWebhooksTest extends TestCase @@ -88,6 +91,18 @@ public function test_it_does_not_call_deleted_webhooks() Queue::assertNothingPushed(); } + public function test_it_listens_to_framework_events() + { + WebhookConfiguration::factory()->create([ + 'events' => [Authenticated::class], + ]); + + $user = User::factory()->create(); + Auth::login($user); + + Queue::assertPushed(ProcessWebhook::class, 1); + } + public function createServer(): Server { return Server::factory()->withNode()->create();