diff --git a/app/Http/Controllers/SocialiteController.php b/app/Http/Controllers/SocialiteController.php index 3f5c5b5..fca73b8 100644 --- a/app/Http/Controllers/SocialiteController.php +++ b/app/Http/Controllers/SocialiteController.php @@ -65,7 +65,11 @@ class SocialiteController extends Controller if ($oauthConnection) { $oauthConnection->update([ 'token' => $providerUser->token, - 'refresh_token' => $providerUser->refreshToken ?? null, + 'refresh_token' => $providerUser->refreshToken ?? '', + 'nickname' => $providerUser->getNickname() ?? '', + 'name' => $providerUser->getName() ?? '', + 'email' => $providerUser->getEmail() ?? '', + 'avatar' => $providerUser->getAvatar() ?? '', ]); return $oauthConnection->user; @@ -84,7 +88,11 @@ class SocialiteController extends Controller 'provider' => $provider, 'provider_id' => $providerUser->getId(), 'token' => $providerUser->token, - 'refresh_token' => $providerUser->refreshToken ?? null, + 'refresh_token' => $providerUser->refreshToken ?? '', + 'nickname' => $providerUser->getNickname() ?? '', + 'name' => $providerUser->getName() ?? '', + 'email' => $providerUser->getEmail() ?? '', + 'avatar' => $providerUser->getAvatar() ?? '', ]); return $user; diff --git a/app/Livewire/Profile/ManageOAuthConnections.php b/app/Livewire/Profile/ManageOAuthConnections.php new file mode 100644 index 0000000..15ece9f --- /dev/null +++ b/app/Livewire/Profile/ManageOAuthConnections.php @@ -0,0 +1,101 @@ + 'refreshUser']; + + /** + * Initializes the component by loading the user’s OAuth connections. + */ + public function mount(): void + { + $this->setName('profile.manage-oauth-connections'); + + $this->user = auth()->user(); + } + + /** + * Sets up the deletion confirmation. + */ + public function confirmConnectionDeletion($connectionId): void + { + $this->confirmingConnectionDeletion = true; + $this->selectedConnectionId = $connectionId; + } + + /** + * Deletes the selected OAuth connection. + */ + public function deleteConnection(): void + { + $connection = $this->user->oauthConnections()->find($this->selectedConnectionId); + + // Ensure the user is authorized to delete the connection. + $this->authorize('delete', $connection); + + // The user must have a password set before removing an OAuth connection. + if ($this->user->password === null) { + $this->addError('password_required', __('You must set a password before removing an OAuth connection.')); + $this->confirmingConnectionDeletion = false; + + return; + } + + if ($connection) { + $connection->delete(); + + $this->user->refresh(); + $this->confirmingConnectionDeletion = false; + $this->selectedConnectionId = null; + + session()->flash('status', __('OAuth connection removed successfully.')); + } else { + session()->flash('error', __('OAuth connection not found.')); + } + } + + /** + * Refreshes the user instance. + */ + public function refreshUser(): void + { + $this->user->refresh(); + } + + /** + * Renders the component view. + */ + public function render(): View + { + return view('livewire.profile.manage-oauth-connections'); + } +} diff --git a/app/Livewire/Profile/UpdatePasswordForm.php b/app/Livewire/Profile/UpdatePasswordForm.php index 0c01ff1..28db4eb 100644 --- a/app/Livewire/Profile/UpdatePasswordForm.php +++ b/app/Livewire/Profile/UpdatePasswordForm.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; use Laravel\Fortify\Contracts\UpdatesUserPasswords; use Laravel\Jetstream\Http\Livewire\UpdatePasswordForm as JetstreamUpdatePasswordForm; +use Override; class UpdatePasswordForm extends JetstreamUpdatePasswordForm { @@ -19,6 +20,7 @@ class UpdatePasswordForm extends JetstreamUpdatePasswordForm * This method has been overwritten to allow a user that has a null password to set a password for their account * without needing to provide their current password. This is useful for users that have been created using OAuth. */ + #[Override] public function updatePassword(UpdatesUserPasswords $updater): void { $this->resetErrorBag(); diff --git a/app/Policies/OAuthConnectionPolicy.php b/app/Policies/OAuthConnectionPolicy.php new file mode 100644 index 0000000..23ae59b --- /dev/null +++ b/app/Policies/OAuthConnectionPolicy.php @@ -0,0 +1,25 @@ +id === $oauthConnection->user_id; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, OAuthConnection $oauthConnection): bool + { + return $user->id === $oauthConnection->user_id && $user->password !== null; + } +} diff --git a/database/migrations/2024_09_26_164844_create_oauth_providers_table.php b/database/migrations/2024_09_26_164844_create_oauth_providers_table.php index 9184073..66a1e32 100644 --- a/database/migrations/2024_09_26_164844_create_oauth_providers_table.php +++ b/database/migrations/2024_09_26_164844_create_oauth_providers_table.php @@ -22,6 +22,10 @@ return new class extends Migration $table->string('provider_id'); $table->string('token')->default(''); $table->string('refresh_token')->default(''); + $table->string('nickname')->default(''); + $table->string('name')->default(''); + $table->string('email')->default(''); + $table->string('avatar')->default(''); $table->timestamps(); $table->unique(['provider', 'provider_id']); diff --git a/resources/views/livewire/profile/manage-oauth-connections.blade.php b/resources/views/livewire/profile/manage-oauth-connections.blade.php new file mode 100644 index 0000000..e3ee43d --- /dev/null +++ b/resources/views/livewire/profile/manage-oauth-connections.blade.php @@ -0,0 +1,95 @@ + + + {{ __('Connected Accounts') }} + + + + {{ __('Manage your connected OAuth accounts.') }} + + + +

+ {{ __('You can manage your OAuth connections here') }} +

+ + @if ($user->password === null) +
+

{{ __('Before you can remove a connection you must have an account password set.') }}

+
+ @endif + + @if (session()->has('status')) +
+ {{ session('status') }} +
+ @endif + + @if (session()->has('error')) +
+ {{ session('error') }} +
+ @endif + +
+ @forelse ($user->oauthConnections as $connection) +
+
+ @switch ($connection->provider) + @case ('discord') + + + + @break + @default + + + + @endswitch +
+ +
+
+ {{ ucfirst($connection->provider) }} - {{ $connection->name }} - {{ $connection->email }} +
+
+ {{ __('Connected') }} {{ $connection->created_at->format('M d, Y') }} +
+
+ +
+ @can('delete', $connection) + + {{ __('Remove') }} + + @endcan +
+
+ @empty +
+ {{ __('You have no connected accounts.') }} +
+ @endforelse +
+ + + + + {{ __('Remove Connected Account') }} + + + + {{ __('Are you sure you want to remove this connected account? This action cannot be undone.') }} + + + + + {{ __('Cancel') }} + + + + {{ __('Remove') }} + + + +
+
diff --git a/resources/views/profile/show.blade.php b/resources/views/profile/show.blade.php index 76bbc77..9ac27a3 100644 --- a/resources/views/profile/show.blade.php +++ b/resources/views/profile/show.blade.php @@ -29,6 +29,12 @@ @endif + {{-- OAuth Management --}} +
+ @livewire('profile.manage-oauth-connections') +
+ + @if (config('session.driver') === 'database')
@livewire('profile.logout-other-browser-sessions-form')