Skip to content

Commit b546efe

Browse files
committed
feat: Added connected profile to connections page
1 parent a569915 commit b546efe

File tree

2 files changed

+95
-1
lines changed

2 files changed

+95
-1
lines changed

app/Livewire/Profile/ConnectionsPage.php

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use App\Models\UserConnection;
99
use Exception;
1010
use Illuminate\Support\Facades\Auth;
11+
use Illuminate\Support\Facades\Http;
1112
use Illuminate\View\View;
1213
use Laravel\Socialite\Facades\Socialite;
1314
use Laravel\Socialite\Two\AbstractProvider;
@@ -58,6 +59,71 @@ public function connect(string $provider): void
5859
$this->redirect(route($route));
5960
}
6061

62+
/**
63+
* Contacts the relevant provider to retrieve basic user account details, such as username, profile link, and avatar URL.
64+
* The data is cached to avoid repetitive API calls when navigating to the connections route.
65+
*
66+
* @return array{username: string|null, link: string|null, avatar_url: string|null} Normalized user details.
67+
*/
68+
public function contactProvider(string $provider): array
69+
{
70+
$baseApiUrl = match ($provider) {
71+
'github' => 'https://api.github.com/user',
72+
'gitlab' => 'https://gitlab.com/api/v4/user',
73+
'bitbucket' => 'https://api.bitbucket.org/2.0/user',
74+
default => throw new RuntimeException("Unsupported provider: {$provider}"),
75+
};
76+
77+
/** @var User $user */
78+
$user = Auth::user();
79+
$connection = $user->connections()->where('provider_name', $provider)->first();
80+
81+
if (! $connection || ! $connection->getAttribute('access_token')) {
82+
throw new RuntimeException("No valid connection found for {$provider}.");
83+
}
84+
85+
// Generate a cache key
86+
$cacheKey = "provider_data:{$provider}:user:{$user->getAttribute('id')}";
87+
88+
return cache()->remember($cacheKey, now()->addMinutes(15), function () use ($baseApiUrl, $provider, $connection): array {
89+
try {
90+
$response = Http::withToken($connection->getAttribute('access_token'))->get($baseApiUrl);
91+
92+
if ($response->failed()) {
93+
throw new RuntimeException("Failed to contact {$provider} API.");
94+
}
95+
96+
$data = $response->json();
97+
98+
// Normalize response
99+
return match ($provider) {
100+
'github' => [
101+
'username' => $data['login'] ?? null,
102+
'link' => $data['html_url'] ?? null,
103+
'avatar_url' => $data['avatar_url'] ?? null,
104+
],
105+
'gitlab' => [
106+
'username' => $data['username'] ?? null,
107+
'link' => $data['web_url'] ?? null,
108+
'avatar_url' => $data['avatar_url'] ?? null,
109+
],
110+
'bitbucket' => [
111+
'username' => $data['username'] ?? ($data['display_name'] ?? null),
112+
'link' => $data['links']['html']['href'] ?? null,
113+
'avatar_url' => $data['links']['avatar']['href'] ?? null,
114+
],
115+
default => ['username' => null, 'link' => null, 'avatar_url' => null],
116+
};
117+
} catch (Exception $e) {
118+
report($e);
119+
Toaster::error("Error retrieving data from {$provider}.");
120+
121+
// Return the structure with null values in case of an error
122+
return ['username' => null, 'link' => null, 'avatar_url' => null];
123+
}
124+
});
125+
}
126+
61127
/**
62128
* Disconnects a service for the current user.
63129
*/
@@ -68,6 +134,10 @@ public function disconnect(string $provider): void
68134
$deleted = $user->connections()->where('provider_name', $provider)->delete();
69135

70136
if ($deleted) {
137+
// Clear cached data for the disconnected provider
138+
$cacheKey = "provider_data:{$provider}:user:{$user->getAttribute('id')}";
139+
cache()->forget($cacheKey);
140+
71141
$this->loadActiveConnections();
72142
Toaster::success(ucfirst($provider) . ' account unlinked successfully!');
73143
} else {
@@ -104,8 +174,13 @@ public function refresh(string $provider): void
104174
$connection->setAttribute('token_expires_at', $newToken->expiresIn ? now()->addSeconds($newToken->expiresIn)->toDateTimeString() : null);
105175
$connection->save();
106176

177+
// Clear cached data for the refreshed provider
178+
$cacheKey = "provider_data:{$provider}:user:{$user->getAttribute('id')}";
179+
cache()->forget($cacheKey);
180+
107181
Toaster::success(ucfirst($provider) . ' token refreshed successfully!');
108-
} catch (Exception) {
182+
} catch (Exception $e) {
183+
report($e);
109184
Toaster::error('Failed to refresh token. Please try re-linking your account.');
110185
}
111186
}

resources/views/livewire/profile/connections-page.blade.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,25 @@ class="w-full justify-center sm:w-auto"
7575
@endif
7676
</div>
7777
</div>
78+
@if ($this->isConnected('github'))
79+
<div
80+
class="mt-3 w-fit rounded-lg border border-gray-300 bg-gray-800 p-1.5 text-xs dark:border-gray-700"
81+
>
82+
{{ __('Connected as') }}
83+
<a
84+
target="_blank"
85+
class="underline"
86+
href="{{ $this->contactProvider('github')['link'] }}"
87+
>
88+
{{ $this->contactProvider('github')['username'] }}
89+
</a>
90+
<img
91+
src="{{ $this->contactProvider('github')['avatar_url'] }}"
92+
title="{{ __('GitHub avatar') }}"
93+
class="mx-3 inline h-5 w-5 rounded-full"
94+
/>
95+
</div>
96+
@endif
7897
</div>
7998
</div>
8099
@endif

0 commit comments

Comments
 (0)