Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 94
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
LinkedInController
0.00% covered (danger)
0.00%
0 / 94
0.00% covered (danger)
0.00%
0 / 9
420
0.00% covered (danger)
0.00%
0 / 1
 callback
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
56
 handleInvitation
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 generateAuthData
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 prepareLoginData
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 redirectUserToFrontend
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 redirect
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOAuthClient
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getUser
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLoginMeta
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Controllers\v1;
4
5use Exception;
6use App\Traits\CompanyAuth;
7use Illuminate\Http\Request;
8use App\Events\User\LoggedIn;
9use App\Helpers\FlyMSGLogger;
10use App\Http\Models\Auth\User;
11use App\Events\User\Registered;
12use App\Http\Models\Invitation;
13use App\Http\Controllers\Controller;
14use App\Http\Models\Passport\Client;
15use Illuminate\Support\Facades\Auth;
16use Illuminate\Support\Facades\Cache;
17use Illuminate\Support\Facades\Log;
18use Laravel\Socialite\Facades\Socialite;
19use MongoDB\BSON\UTCDateTime;
20
21class LinkedInController extends Controller
22{
23    use CompanyAuth;
24    /**
25     * LinkedIn Callback url.
26     */
27    public function callback()
28    {
29        try {
30            $user = Socialite::driver('linkedin-openid')->stateless()->user();
31
32            $liAccessToken = $user->token;
33            $linkedinUser = User::where('email', $user->email)->first();
34
35            if ($linkedinUser === null) {
36                $invitation = $this->handleInvitation($user);
37
38                $linkedinUser = User::create([
39                    'email' => $user->email,
40                    'first_name' => $user->first_name,
41                    'last_name' => $user->last_name,
42                    'avatar' => $user->avatar,
43                    'oauth_id' => $user->id,
44                    'oauth_type' => 'linkedin',
45                    'signup_source' => 'linkedin',
46                    'refered_by' => $invitation['user_id'] ?? '',
47                    'email_verified_at' => new UTCDateTime(now()->getTimestamp() * 1000),
48                    'onboardingv2_presented' => true
49                ]);
50
51                $linkedinUser = User::where('email', $user->email)->first();
52
53                event(new Registered($linkedinUser));
54            }
55
56            if ($linkedinUser) {
57                Auth::login($linkedinUser);
58                $authData = $this->generateAuthData($liAccessToken);
59                $authRequest = Request::create(route('passport.token'), 'POST', $authData);
60                $response = app()->handle($authRequest);
61                $data = json_decode($response->getContent(), true);
62
63                if (isset($data['access_token'])) {
64                    $data = $this->prepareLoginData($data, $liAccessToken);
65                    $user = $this->getUser($data['email']);
66                    if ($user) {
67                        LoggedIn::dispatch($user, ['email' => $user->email, 'signin_source' => 'linkedin']);
68                    } else {
69                        Log::error("LinkedInController::User not found", ['email' => $data['email']]);
70                    }
71
72                    $extensionAuthData = $this->generateAuthData($liAccessToken);
73                    $extensionAuthRequest = Request::create(route('passport.token'), 'POST', $extensionAuthData);
74                    $extensionResponse = app()->handle($extensionAuthRequest);
75                    $extensionData = json_decode($extensionResponse->getContent(), true);
76
77                    if (isset($extensionData['access_token'])) {
78                        $extensionData = $this->prepareLoginData($extensionData, $liAccessToken);
79                        $user = $this->getUser($extensionData['email']);
80
81                        $data['extension'] = $extensionData;
82                    }
83
84                    return $this->redirectUserToFrontend($data);
85                } else {
86                    $data = ['error' => trans('auth.failed')];
87                    return response()->json($data);
88                }
89            }
90        } catch (Exception $e) {
91            FlyMSGLogger::logError("LinkedInController", $e);
92            return redirect()->to(env('LINKEDIN_SIGNIN_URL', 'https://app.vengreso.com/session/signin'));
93        }
94    }
95
96    private function handleInvitation($user)
97    {
98        $invitation = [];
99
100        if (isset($user->invitation_id) && $user->invitation_id !== '') {
101            $searchArray = ['_id' => $user->invitation_id];
102            $invitation = Invitation::where($searchArray)->first();
103            $invitation->status = true;
104            $invitation->save();
105        }
106
107        return $invitation;
108    }
109
110    private function generateAuthData($liAccessToken)
111    {
112        $client = $this->getOAuthClient();
113
114        return [
115            'grant_type' => 'social',
116            'client_id' => $client->id,
117            'client_secret' => $client->secret,
118            'provider' => 'linkedin-openid',
119            'access_token' => $liAccessToken,
120        ];
121    }
122
123    private function prepareLoginData($data, $liAccessToken)
124    {
125        $providerUser = Socialite::driver('linkedin-openid')->stateless()->userFromToken($liAccessToken);
126        $email = $providerUser->getEmail();
127        $user = $this->getUser($email);
128
129        if (filled($user->deleted_at)) {
130            $data['error_code'] = "DEACTIVATED";
131            $data['admin_email'] = $user?->company?->pocs()?->first()?->email;
132        }
133
134        $user['id'] = $user->_id;
135        $sessionExpiry = config('auth.passport.refresh_token_expiry');
136        $data['session_expires_in'] = intval($sessionExpiry);
137        $user['is_poc'] = $user->isPOC();
138        $data['user_details'] = $user;
139        $data['provider'] = 'linkedin';
140        $data['li_access_token'] = $liAccessToken;
141        $data['email'] = $email;
142
143        $about = $this->handleAdminInvitation($user);
144
145        if ($about && $about['company_poc']) {
146            $data['is_company_poc'] = $about['company_poc'];
147        }
148
149        return array_merge($data, $this->getLoginMeta());
150    }
151
152    private function redirectUserToFrontend($data)
153    {
154        $uniqueId = uniqid('login_', true);
155
156        Log::info('Redirecting user to frontend', ['uniqueId' => $uniqueId, 'data' => $data]);
157
158        Cache::put($uniqueId, $data, 60);
159
160        $url = "signin/{$uniqueId}/linkedin";
161
162        echo '<script>';
163        echo 'var result = ' . json_encode(['urlRedirect' => $url]) . ';';
164        echo 'var base64_result = btoa(JSON.stringify(result))' . ';';
165        echo "var app_url ='" . env('LINKEDIN_SIGNIN_URL', 'https://app.vengreso.com/session/signin') . "?params='" . ';';
166        echo 'var final_url = app_url+base64_result;';
167        echo 'location.href= final_url' . ';';
168        echo '</script>';
169    }
170
171    /**
172     * Redirect the user to the LinkedIn Login Page
173     */
174    public function redirect()
175    {
176        return Socialite::driver('linkedin-openid')->stateless()->redirect();
177    }
178
179    protected function getOAuthClient()
180    {
181        $searchArray = ['password_client' => true];
182
183        return Client::where($searchArray)->first();
184    }
185
186    protected function getUser($email)
187    {
188        return User::withTrashed()->firstWhere('email', $email);
189    }
190
191    protected function getLoginMeta()
192    {
193        return [];
194    }
195}