diff --git a/app/Actions/AuthenticateSocialUser.php b/app/Actions/AuthenticateSocialUser.php index 5d2d0b1..e38b578 100644 --- a/app/Actions/AuthenticateSocialUser.php +++ b/app/Actions/AuthenticateSocialUser.php @@ -71,7 +71,6 @@ class AuthenticateSocialUser ->first(); if (! $user) { - abort_if($data['intent'] !== 'register', 422, 'SOCIAL_ACCOUNT_NOT_FOUND'); abort_if(($data['termsAccepted'] ?? false) !== true, 422, 'TERMS_ACCEPTANCE_REQUIRED'); $user = User::create([ diff --git a/tests/Feature/MobileSocialAuthenticationTest.php b/tests/Feature/MobileSocialAuthenticationTest.php index 7afa63c..fdae05f 100644 --- a/tests/Feature/MobileSocialAuthenticationTest.php +++ b/tests/Feature/MobileSocialAuthenticationTest.php @@ -215,20 +215,31 @@ it('requires an authorization code for Apple authentication', function () { ->assertJsonValidationErrors('authorizationCode'); }); -it('does not create an unknown account from the login intent', function () { +it('creates an unknown account from the login intent', function () { bindResolvedSocialIdentity([ 'id' => 'unknown-google-user', + 'name' => 'Unknown Google User', 'email' => 'unknown@example.com', ]); $this->postJson('/api/auth/mobile/social', socialLoginPayload([ 'intent' => 'login', - 'termsAccepted' => false, + 'termsAccepted' => true, ])) - ->assertUnprocessable() - ->assertJsonPath('code', 'SOCIAL_ACCOUNT_NOT_FOUND'); + ->assertOk() + ->assertJsonPath('user.name', 'unknown.google.user') + ->assertJsonStructure(['token']); - expect(User::count())->toBe(0); + $user = User::query()->where('email', 'unknown@example.com')->firstOrFail(); + + expect($user->terms_accepted_at)->not->toBeNull() + ->and($user->socialAccounts)->toHaveCount(1); + + $this->assertDatabaseHas('social_accounts', [ + 'provider' => SocialProvider::Google->value, + 'provider_user_id' => 'unknown-google-user', + 'user_id' => $user->getKey(), + ]); }); it('requires terms acceptance before creating a social account', function () { @@ -238,6 +249,7 @@ it('requires terms acceptance before creating a social account', function () { ]); $this->postJson('/api/auth/mobile/social', socialLoginPayload([ + 'intent' => 'login', 'termsAccepted' => false, ])) ->assertUnprocessable() @@ -246,6 +258,32 @@ it('requires terms acceptance before creating a social account', function () { expect(User::count())->toBe(0); }); +it('generates a unique username when the Google name is already taken', function () { + User::factory()->create([ + 'name' => 'camille.martin', + 'email' => 'existing-name@example.com', + ]); + + bindResolvedSocialIdentity([ + 'id' => 'google-duplicate-name', + 'name' => 'Camille Martin', + 'email' => 'new-camille@example.com', + ]); + + $response = $this->postJson('/api/auth/mobile/social', socialLoginPayload([ + 'intent' => 'login', + 'termsAccepted' => true, + ])); + + $response->assertOk(); + + $generatedName = $response->json('user.name'); + + expect($generatedName) + ->not->toBe('camille.martin') + ->toStartWith('camille.martin-'); +}); + it('rejects an identity whose provider email is not verified', function () { bindResolvedSocialIdentity([ 'id' => 'unverified-google-user',