diff --git a/routes/socialstream-inertia.php b/routes/socialstream-inertia.php index baad6494..15a0dbba 100644 --- a/routes/socialstream-inertia.php +++ b/routes/socialstream-inertia.php @@ -10,8 +10,7 @@ Route::group(['middleware' => config('socialstream.middleware', ['web'])], function () { Route::get('/oauth/{provider}', [OAuthController::class, 'redirect'])->name('oauth.redirect'); - Route::get('/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); - Route::post('/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); + Route::match(['get', 'post'], '/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); Route::delete('/user/connected-account/{id}', [ConnectedAccountController::class, 'destroy']) ->middleware(['auth']) diff --git a/routes/socialstream.php b/routes/socialstream.php index 11eb2820..25de99c9 100644 --- a/routes/socialstream.php +++ b/routes/socialstream.php @@ -5,6 +5,5 @@ Route::group(['middleware' => config('socialstream.middleware', ['web'])], function () { Route::get('/oauth/{provider}', [OAuthController::class, 'redirect'])->name('oauth.redirect'); - Route::get('/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); - Route::post('/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); + Route::match(['get', 'post'], '/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); }); diff --git a/src/Actions/AuthenticateOAuthCallback.php b/src/Actions/AuthenticateOAuthCallback.php index ee09dfad..3bb39bd1 100644 --- a/src/Actions/AuthenticateOAuthCallback.php +++ b/src/Actions/AuthenticateOAuthCallback.php @@ -99,10 +99,10 @@ class_exists(FortifyFeatures::class) && protected function alreadyAuthenticated(Authenticatable $user, ?ConnectedAccount $account, string $provider, ProviderUser $providerAccount): RedirectResponse { // Get the route - $route = match(true) { + $route = match (true) { Route::has('filament.admin.home') => route('filament.admin.home'), Route::has('filament.home') => route('filament.home'), - $this->hasComposerPackage('laravel/breeze') => match(true) { + $this->hasComposerPackage('laravel/breeze') => match (true) { Route::has('profile.show') => route('profile.show'), Route::has('profile.edit') => route('profile.edit'), Route::has('profile') => route('profile'), diff --git a/src/ConnectedAccount.php b/src/ConnectedAccount.php index f1d6956f..c1c669d0 100644 --- a/src/ConnectedAccount.php +++ b/src/ConnectedAccount.php @@ -13,8 +13,8 @@ class ConnectedAccount extends Model { use HasFactory; - use HasTimestamps; use HasOAuth2Tokens; + use HasTimestamps; /** * The attributes that are mass assignable. diff --git a/src/Policies/ConnectedAccountPolicy.php b/src/Policies/ConnectedAccountPolicy.php index b4b29244..e4471bb7 100644 --- a/src/Policies/ConnectedAccountPolicy.php +++ b/src/Policies/ConnectedAccountPolicy.php @@ -2,9 +2,9 @@ namespace JoelButcher\Socialstream\Policies; -use JoelButcher\Socialstream\ConnectedAccount; use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; +use JoelButcher\Socialstream\ConnectedAccount; class ConnectedAccountPolicy { diff --git a/src/SocialstreamServiceProvider.php b/src/SocialstreamServiceProvider.php index 0b4da4d0..7a459e9d 100644 --- a/src/SocialstreamServiceProvider.php +++ b/src/SocialstreamServiceProvider.php @@ -198,7 +198,7 @@ protected function bootLaravelJetstream(): void } Socialstream::setUserPasswordsUsing(SetUserPassword::class); - Socialstream::createUsersFromProviderUsing(match(Jetstream::hasTeamFeatures()) { + Socialstream::createUsersFromProviderUsing(match (Jetstream::hasTeamFeatures()) { true => CreateUserWithTeamsFromProvider::class, false => CreateUserFromProvider::class, }); @@ -216,7 +216,6 @@ protected function bootLaravelJetstream(): void }); } - if (! $this->app->runningInConsole()) { return; } diff --git a/tests/Feature/RouteCachingTest.php b/tests/Feature/RouteCachingTest.php new file mode 100644 index 00000000..9c889bf1 --- /dev/null +++ b/tests/Feature/RouteCachingTest.php @@ -0,0 +1,80 @@ +defineCacheRoutes(file_get_contents( + __DIR__.'/../../workbench/routes/web.php' + )); + + get('/oauth/github') + ->assertRedirect(); +}); + +it('caches routes and authenticates via GET', function () { + $this->defineCacheRoutes(file_get_contents( + __DIR__.'/../../workbench/routes/web.php' + )); + + $user = (new SocialiteUser()) + ->map([ + 'id' => fake()->numerify('########'), + 'nickname' => 'joel', + 'name' => 'Joel', + 'email' => 'joel@socialstream.dev', + 'avatar' => null, + 'avatar_original' => null, + ]) + ->setToken('user-token') + ->setRefreshToken('refresh-token') + ->setExpiresIn(3600); + + $provider = Mockery::mock(GithubProvider::class); + $provider->shouldReceive('user')->once()->andReturn($user); + + Socialite::shouldReceive('driver')->once()->with('github')->andReturn($provider); + + session()->put('socialstream.previous_url', route('register')); + + get('oauth/github/callback')->assertRedirect(RouteServiceProvider::HOME); +}); + +it('caches routes and authenticates via POST', function () { + $this->defineCacheRoutes(file_get_contents( + __DIR__.'/../../workbench/routes/web.php' + )); + + $user = (new SocialiteUser()) + ->map([ + 'id' => fake()->numerify('########'), + 'nickname' => 'joel', + 'name' => 'Joel', + 'email' => 'joel@socialstream.dev', + 'avatar' => null, + 'avatar_original' => null, + ]) + ->setToken('user-token') + ->setRefreshToken('refresh-token') + ->setExpiresIn(3600); + + $provider = Mockery::mock(GithubProvider::class); + $provider->shouldReceive('user')->once()->andReturn($user); + + Socialite::shouldReceive('driver')->once()->with('github')->andReturn($provider); + + session()->put('socialstream.previous_url', route('register')); + + post('oauth/github/callback')->assertRedirect(RouteServiceProvider::HOME); +}); diff --git a/tests/Feature/SocialstreamTest.php b/tests/Feature/SocialstreamTest.php index 284fd850..226c60df 100644 --- a/tests/Feature/SocialstreamTest.php +++ b/tests/Feature/SocialstreamTest.php @@ -5,7 +5,6 @@ use App\Models\User; use App\Providers\RouteServiceProvider; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Route; @@ -18,9 +17,10 @@ use Laravel\Socialite\Two\User as SocialiteUser; use Mockery; use Symfony\Component\HttpFoundation\RedirectResponse; + use function Pest\Laravel\get; -uses(WithFaker::class, RefreshDatabase::class); +uses(RefreshDatabase::class); it('redirects users', function (): void { $response = get('http://localhost/oauth/github'); @@ -74,7 +74,7 @@ public function generate(string $provider): RedirectResponse test('users can register', function (): void { $user = (new SocialiteUser()) ->map([ - 'id' => $githubId = $this->faker->numerify('########'), + 'id' => $githubId = fake()->numerify('########'), 'nickname' => 'joel', 'name' => 'Joel', 'email' => 'joel@socialstream.dev', @@ -114,7 +114,7 @@ public function generate(string $provider): RedirectResponse $user->connectedAccounts()->create([ 'provider' => 'github', - 'provider_id' => $githubId = $this->faker->numerify('########'), + 'provider_id' => $githubId = fake()->numerify('########'), 'email' => 'joel@socialstream.dev', 'token' => Str::random(64), ]); @@ -162,7 +162,7 @@ public function generate(string $provider): RedirectResponse $user = (new SocialiteUser()) ->map([ - 'id' => $githubId = $this->faker->numerify('########'), + 'id' => $githubId = fake()->numerify('########'), 'nickname' => 'joel', 'name' => 'Joel', 'email' => 'joel@socialstream.dev', @@ -199,7 +199,7 @@ public function generate(string $provider): RedirectResponse $user = (new SocialiteUser()) ->map([ - 'id' => $githubId = $this->faker->numerify('########'), + 'id' => $githubId = fake()->numerify('########'), 'nickname' => 'joel', 'name' => 'Joel', 'email' => 'joel@socialstream.dev', @@ -242,7 +242,7 @@ public function generate(string $provider): RedirectResponse $user = (new SocialiteUser()) ->map([ - 'id' => $githubId = $this->faker->numerify('########'), + 'id' => $githubId = fake()->numerify('########'), 'nickname' => 'joel', 'name' => 'Joel', 'email' => 'joel@socialstream.dev', @@ -278,7 +278,7 @@ public function generate(string $provider): RedirectResponse $user = (new SocialiteUser()) ->map([ - 'id' => $githubId = $this->faker->numerify('########'), + 'id' => $githubId = fake()->numerify('########'), 'nickname' => 'joel', 'name' => 'Joel', 'avatar' => null, diff --git a/tests/TestCase.php b/tests/TestCase.php index 51b8ce4e..a6d285f8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,7 +2,6 @@ namespace JoelButcher\Socialstream\Tests; -use Illuminate\Support\Facades\Config; use JoelButcher\Socialstream\SocialstreamServiceProvider; use Laravel\Socialite\SocialiteServiceProvider; use Mockery; @@ -10,19 +9,10 @@ abstract class TestCase extends BaseTestCase { - protected function setUp(): void - { - parent::setUp(); - - Config::set('services.github', [ - 'client_id' => 'github-client-id', - 'client_secret' => 'github-client-secret', - 'redirect' => 'https://example.test/oauth/github/callback', - ]); - } - protected function tearDown(): void { + parent::tearDown(); + Mockery::close(); } @@ -43,6 +33,12 @@ protected function getEnvironmentSetUp($app): void 'database' => ':memory:', 'prefix' => '', ]); + + $app['config']->set('services.github', [ + 'client_id' => 'github-client-id', + 'client_secret' => 'github-client-secret', + 'redirect' => 'https://example.test/oauth/github/callback', + ]); } protected function migrate(): void diff --git a/workbench/routes/web.php b/workbench/routes/web.php new file mode 100644 index 00000000..3a9cf66f --- /dev/null +++ b/workbench/routes/web.php @@ -0,0 +1,17 @@ + config('socialstream.middleware', ['web'])], function () { + Route::get('/oauth/{provider}', [OAuthController::class, 'redirect'])->name('oauth.redirect'); + Route::match(['get', 'post'], '/oauth/{provider}/callback', [OAuthController::class, 'callback'])->name('oauth.callback'); +}); + +Route::post('/login', function () { + return 'login'; +})->name('login'); + +Route::post('/register', function () { + return 'register'; +})->name('register');