Merge branch 'main' into chore/rename-channels-tab

This commit is contained in:
Paulo Castellano 2026-06-10 16:30:02 -03:00 committed by GitHub
commit 8dad00d4df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 65 additions and 23 deletions

View file

@ -102,7 +102,10 @@ SPACES_BUCKET=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
LINKEDIN_CLIENT_REDIRECT="${APP_URL}/accounts/linkedin/callback"
# LINKEDIN_SCOPES="openid,profile,email,w_member_social"
LINKEDIN_PAGE_CLIENT_REDIRECT="${APP_URL}/accounts/linkedin-page/callback"
LINKEDIN_PAGE_CLIENT_REDIRECT="${APP_URL}/accounts/linkedin-page/callback"
# LINKEDIN_PAGE_SCOPES="openid,profile,email,w_organization_social,r_organization_social,rw_organization_admin,w_member_social"
# X / Twitter (https://developer.twitter.com)
X_CLIENT_ID=

View file

@ -22,14 +22,6 @@ class LinkedInController extends SocialController
protected SocialPlatform $platform = SocialPlatform::LinkedIn;
protected array $scopes = [
'openid',
'profile',
'email',
'r_basicprofile',
'w_member_social',
];
public function connect(Request $request): Response|RedirectResponse
{
$this->ensurePlatformEnabled();
@ -42,7 +34,7 @@ public function connect(Request $request): Response|RedirectResponse
$this->authorize('manageAccounts', $workspace);
return $this->redirectToProvider($request, $this->driver, $this->scopes);
return $this->redirectToProvider($request, $this->driver, config('trypost.platforms.linkedin.scopes'));
}
public function callback(Request $request): View

View file

@ -24,16 +24,6 @@ class LinkedInPageController extends SocialController
protected SocialPlatform $platform = SocialPlatform::LinkedInPage;
protected array $scopes = [
'openid',
'profile',
'email',
'w_organization_social',
'r_organization_social',
'rw_organization_admin',
'w_member_social',
];
public function connect(Request $request): SymfonyResponse|RedirectResponse
{
$this->ensurePlatformEnabled();
@ -55,7 +45,7 @@ public function connect(Request $request): SymfonyResponse|RedirectResponse
return Inertia::location(
Socialite::driver($this->driver)
->scopes($this->scopes)
->scopes(config('trypost.platforms.linkedin-page.scopes'))
->with([
'redirect_uri' => config('services.linkedin-openid.redirect_page'),
])
@ -80,7 +70,7 @@ public function callback(Request $request): View|RedirectResponse
try {
$socialUser = Socialite::driver($this->driver)
->scopes($this->scopes)
->scopes(config('trypost.platforms.linkedin-page.scopes'))
->with([
'redirect_uri' => config('services.linkedin-openid.redirect_page'),
])

View file

@ -80,10 +80,14 @@
'api' => env('LINKEDIN_API', 'https://api.linkedin.com'),
// OAuth host is different from the data API (api.linkedin.com).
'oauth_api' => env('LINKEDIN_OAUTH_API', 'https://www.linkedin.com'),
// Scopes for LinkedIn authentication
'scopes' => array_values(array_filter(array_map('trim', explode(',', (string) env('LINKEDIN_SCOPES', 'openid,profile,email,w_member_social'))))),
],
'linkedin-page' => [
'enabled' => env('LINKEDIN_PAGE_ENABLED', true),
'api' => env('LINKEDIN_PAGE_API', 'https://api.linkedin.com'),
// Scopes for LinkedIn Page authentication
'scopes' => array_values(array_filter(array_map('trim', explode(',', (string) env('LINKEDIN_PAGE_SCOPES', 'openid,profile,email,w_organization_social,r_organization_social,rw_organization_admin,w_member_social'))))),
],
'x' => [
'enabled' => env('X_ENABLED', true),

View file

@ -89,7 +89,9 @@ R2_URL=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
LINKEDIN_CLIENT_REDIRECT="${APP_URL}/accounts/linkedin/callback"
# LINKEDIN_SCOPES="openid,profile,email,w_member_social"
LINKEDIN_PAGE_CLIENT_REDIRECT="${APP_URL}/accounts/linkedin-page/callback"
# LINKEDIN_PAGE_SCOPES="openid,profile,email,w_organization_social,r_organization_social,rw_organization_admin,w_member_social"
X_CLIENT_ID=
X_CLIENT_SECRET=

View file

@ -39,6 +39,57 @@
expect(session('social_connect_workspace'))->toBe($this->workspace->id);
});
/**
* Mock the LinkedIn Socialite driver, hit /connect, and return the scopes
* the controller requested.
*
* @return array<int, string>
*/
$captureConnectScopes = function (object $test): array {
$captured = [];
$driverMock = Mockery::mock();
$driverMock->shouldReceive('scopes')
->withArgs(function (array $scopes) use (&$captured) {
$captured = $scopes;
return true;
})
->andReturnSelf();
$driverMock->shouldReceive('redirect')->andReturn(Mockery::mock([
'getTargetUrl' => 'https://www.linkedin.com/oauth/v2/authorization?test=1',
]));
Socialite::shouldReceive('driver')
->with('linkedin')
->andReturn($driverMock);
$test->actingAs($test->user)
->withHeader('X-Inertia', 'true')
->get(route('app.social.linkedin.connect'));
return $captured;
};
test('linkedin connect requests the default scope set', function () use ($captureConnectScopes) {
config(['trypost.platforms.linkedin.scopes' => ['openid', 'profile', 'email', 'w_member_social']]);
expect($captureConnectScopes($this))->toEqualCanonicalizing([
'openid', 'profile', 'email', 'w_member_social',
]);
});
test('linkedin connect requests the scopes configured via LINKEDIN_SCOPES', function () use ($captureConnectScopes) {
// Operators whose LinkedIn app has legacy/enterprise products approved
// override the default set via LINKEDIN_SCOPES (exploded into the config
// array), e.g. re-adding r_basicprofile to restore the vanityName lookup.
config(['trypost.platforms.linkedin.scopes' => ['openid', 'profile', 'email', 'w_member_social', 'r_basicprofile']]);
expect($captureConnectScopes($this))->toEqualCanonicalizing([
'openid', 'profile', 'email', 'w_member_social', 'r_basicprofile',
]);
});
test('linkedin oauth callback creates account', function () {
session([
'social_connect_workspace' => $this->workspace->id,
@ -99,7 +150,7 @@
// splits on space (the OAuth 2.0 default), so approvedScopes lands as
// a single-element array with the whole CSV inside. The save path
// must normalize back to individual tokens.
$socialiteUser->approvedScopes = ['email,openid,profile,r_basicprofile,w_member_social'];
$socialiteUser->approvedScopes = ['email,openid,profile,w_member_social'];
Socialite::shouldReceive('driver')
->with('linkedin')
@ -116,7 +167,7 @@
$account = SocialAccount::where('platform_user_id', 'abc123xyz')->first();
expect($account->scopes)->toEqualCanonicalizing([
'email', 'openid', 'profile', 'r_basicprofile', 'w_member_social',
'email', 'openid', 'profile', 'w_member_social',
]);
});