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