8
8
use App \Models \UserConnection ;
9
9
use Exception ;
10
10
use Illuminate \Support \Facades \Auth ;
11
+ use Illuminate \Support \Facades \Http ;
11
12
use Illuminate \View \View ;
12
13
use Laravel \Socialite \Facades \Socialite ;
13
14
use Laravel \Socialite \Two \AbstractProvider ;
@@ -58,6 +59,71 @@ public function connect(string $provider): void
58
59
$ this ->redirect (route ($ route ));
59
60
}
60
61
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
+
61
127
/**
62
128
* Disconnects a service for the current user.
63
129
*/
@@ -68,6 +134,10 @@ public function disconnect(string $provider): void
68
134
$ deleted = $ user ->connections ()->where ('provider_name ' , $ provider )->delete ();
69
135
70
136
if ($ deleted ) {
137
+ // Clear cached data for the disconnected provider
138
+ $ cacheKey = "provider_data: {$ provider }:user: {$ user ->getAttribute ('id ' )}" ;
139
+ cache ()->forget ($ cacheKey );
140
+
71
141
$ this ->loadActiveConnections ();
72
142
Toaster::success (ucfirst ($ provider ) . ' account unlinked successfully! ' );
73
143
} else {
@@ -104,8 +174,13 @@ public function refresh(string $provider): void
104
174
$ connection ->setAttribute ('token_expires_at ' , $ newToken ->expiresIn ? now ()->addSeconds ($ newToken ->expiresIn )->toDateTimeString () : null );
105
175
$ connection ->save ();
106
176
177
+ // Clear cached data for the refreshed provider
178
+ $ cacheKey = "provider_data: {$ provider }:user: {$ user ->getAttribute ('id ' )}" ;
179
+ cache ()->forget ($ cacheKey );
180
+
107
181
Toaster::success (ucfirst ($ provider ) . ' token refreshed successfully! ' );
108
- } catch (Exception ) {
182
+ } catch (Exception $ e ) {
183
+ report ($ e );
109
184
Toaster::error ('Failed to refresh token. Please try re-linking your account. ' );
110
185
}
111
186
}
0 commit comments