From 10f612a90199cdd8529773ea3b319a4b627e38d5 Mon Sep 17 00:00:00 2001 From: Flycro Date: Thu, 19 Mar 2026 23:14:57 +0100 Subject: [PATCH] feat: make user password nullable for social-only accounts --- app/Models/User.php | 37 ++++++++++++++++--- database/factories/UserFactory.php | 13 ++++++- ..._19_212004_make_user_password_nullable.php | 28 ++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 database/migrations/2026_03_19_212004_make_user_password_nullable.php diff --git a/app/Models/User.php b/app/Models/User.php index 0908906..62b56ee 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,17 +2,18 @@ namespace App\Models; -// use Illuminate\Contracts\Auth\MustVerifyEmail; +use Database\Factories\UserFactory; +use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; -use Laravel\Sanctum\HasApiTokens; -class User extends Authenticatable +class User extends Authenticatable implements MustVerifyEmail { - /** @use HasFactory<\Database\Factories\UserFactory> */ - use HasApiTokens, HasFactory, Notifiable; + /** @use HasFactory */ + use HasFactory, Notifiable; /** * The attributes that are mass assignable. @@ -59,6 +60,32 @@ class User extends Authenticatable ]; } + /** + * Only send verification notification when the feature is enabled. + */ + public function sendEmailVerificationNotification(): void + { + if (config('auth-ui.features.email_verification')) { + parent::sendEmailVerificationNotification(); + } + } + + /** + * Check if the user has a password set (i.e. not a social-only user). + */ + public function hasPassword(): bool + { + return $this->password !== null; + } + + /** + * Get the user's social accounts. + */ + public function socialAccounts(): HasMany + { + return $this->hasMany(SocialAccount::class); + } + /** * Get the user's full name. */ diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index c3fa181..b365213 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -2,12 +2,13 @@ namespace Database\Factories; +use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; /** - * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User> + * @extends Factory */ class UserFactory extends Factory { @@ -43,4 +44,14 @@ class UserFactory extends Factory 'email_verified_at' => null, ]); } + + /** + * Indicate that the user was created via social login (no password). + */ + public function social(): static + { + return $this->state(fn (array $attributes) => [ + 'password' => null, + ]); + } } diff --git a/database/migrations/2026_03_19_212004_make_user_password_nullable.php b/database/migrations/2026_03_19_212004_make_user_password_nullable.php new file mode 100644 index 0000000..3bd91b0 --- /dev/null +++ b/database/migrations/2026_03_19_212004_make_user_password_nullable.php @@ -0,0 +1,28 @@ +string('password')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->string('password')->nullable(false)->change(); + }); + } +};