LoginController::handleProviderCallback()   B
last analyzed

Complexity

Conditions 9
Paths 65

Size

Total Lines 79
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 48
nc 65
nop 1
dl 0
loc 79
rs 7.5789
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Http\Controllers\Auth;
4
5
use App\Http\Controllers\Controller;
6
use App\Jobs\Tenant\CreateDBs;
7
use App\Jobs\Tenant\Migration;
8
use App\Models\Company;
9
use App\Models\Person;
10
use App\Models\Tenant;
11
use App\Models\User;
12
use App\Models\UserSocial;
13
use App\Traits\Login;
14
use Exception;
15
use Illuminate\Foundation\Auth\AuthenticatesUsers;
16
use Illuminate\Http\Request;
17
use Illuminate\Support\Facades\App;
18
use Illuminate\Support\Facades\Auth;
19
use Illuminate\Support\Str;
20
use Illuminate\Validation\ValidationException;
21
use Laravel\Socialite\Facades\Socialite;
22
use LaravelEnso\Core\Events\Login as Event;
23
use LaravelEnso\Core\Traits\Logout;
24
use LaravelEnso\Roles\Models\Role;
25
use LaravelEnso\UserGroups\Models\UserGroup;
26
27
class LoginController extends Controller
28
{
29
    /**
30
     * @var mixed
31
     */
32
    public $maxAttempts;
33
    use AuthenticatesUsers, Logout, Login {
0 ignored issues
show
introduced by
The trait Illuminate\Foundation\Auth\AuthenticatesUsers requires some properties which are not provided by App\Http\Controllers\Auth\LoginController: $redirectTo, $decayMinutes
Loading history...
Bug introduced by
The trait App\Traits\Login requires the property $attributes which is not provided by App\Http\Controllers\Auth\LoginController.
Loading history...
Bug introduced by
The trait LaravelEnso\Core\Traits\Logout requires the property $attributes which is not provided by App\Http\Controllers\Auth\LoginController.
Loading history...
34
        Logout::logout insteadof AuthenticatesUsers;
35
        Login::login insteadof AuthenticatesUsers;
36
    }
37
38
    // protected $redirectTo = '/';
39
40
    private ?User $user = null;
41
42
    public function __construct()
43
    {
44
        $this->middleware('guest')->except('logout');
45
46
        $this->maxAttempts = config('enso.auth.maxLoginAttempts');
47
    }
48
49
    public function redirect($service)
50
    {
51
        return Socialite::driver($service)->redirect();
52
    }
53
54
    public function redirectToProvider($provider)
55
    {
56
        $validated = $this->validateProvider($provider);
57
        if (! is_null($validated)) {
58
            return $validated;
59
        }
60
61
        return Socialite::driver($provider)->stateless()->redirect();
0 ignored issues
show
Bug introduced by
The method stateless() does not exist on Laravel\Socialite\Contracts\Provider. It seems like you code against a sub-type of Laravel\Socialite\Contracts\Provider such as Laravel\Socialite\Two\AbstractProvider. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
        return Socialite::driver($provider)->/** @scrutinizer ignore-call */ stateless()->redirect();
Loading history...
62
    }
63
64
    /**
65
     * Obtain the user information from Provider.
66
     *
67
     * @param  $provider
68
     * @return JsonResponse
0 ignored issues
show
Bug introduced by
The type App\Http\Controllers\Auth\JsonResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
69
     */
70
    public function handleProviderCallback($provider)
71
    {
72
        try {
73
            $user = Socialite::driver($provider)->stateless()->user();
74
        } catch (Exception) {
75
            return redirect(config('settings.clientBaseUrl').'/social-callback?token=&status=false&message=Invalid credentials provided!');
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect(config('...credentials provided!') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type App\Http\Controllers\Auth\JsonResponse.
Loading history...
76
        }
77
78
        $curUser = User::where('email', $user->getEmail())->first();
79
80
        if (! $curUser) {
81
            try {
82
                // create person
83
                $person = new Person();
84
                $name = $user->getName();
85
                $person->name = $name;
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on App\Models\Person. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
86
                $person->email = $user->getEmail();
0 ignored issues
show
Bug introduced by
The property email does not seem to exist on App\Models\Person. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
87
                $person->save();
88
                // get user_group_id
89
                $user_group = UserGroup::where('name', 'Administrators')->first();
90
                if ($user_group === null) {
91
                    // create user_group
92
                    $user_group = UserGroup::create(['name' => 'Administrators', 'description' => 'Administrator users group']);
93
                }
94
95
                // get role_id
96
                $role = Role::where('name', 'free')->first();
97
                if ($role === null) {
98
                    $role = Role::create(['menu_id' => 1, 'name' => 'supervisor', 'display_name' => 'Supervisor', 'description' => 'Supervisor role.']);
99
                }
100
101
                $curUser = User::create(
102
                    [
103
                        'email' => $user->getEmail(),
104
                        'person_id' => $person->id,
105
                        'group_id' => $user_group->id,
106
                        'role_id' => $role->id,
107
                        'email_verified_at' => now(),
108
                        'is_active' => 1,
109
                    ],
110
                );
111
112
                $random = $this->unique_random('companies', 'name', 5);
113
                $company = Company::create([
114
                    'name' => 'company'.$random,
115
                    'email' => $user->getEmail(),
116
                    'is_tenant' => 1,
117
                    'status' => 1,
118
                ]);
119
120
                $person->companies()->attach($company->id, ['person_id' => $person->id, 'is_main' => 1, 'is_mandatary' => 1, 'company_id' => $company->id]);
121
122
                // Dispatch Tenancy Jobs
123
                CreateDBs::dispatch($company);
124
                Migration::dispatch($company, $user->name, $user->email, $user->password);
125
            } catch (Exception) {
126
                return redirect(config('settings.clientBaseUrl').'/social-callback?token=&status=false&message=Something went wrong!');
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect(config('...Something went wrong!') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type App\Http\Controllers\Auth\JsonResponse.
Loading history...
127
            }
128
        }
129
130
        try {
131
            if ($this->needsToCreateSocial($curUser, $provider)) {
132
                UserSocial::create([
133
                    'user_id' => $curUser->id,
134
                    'social_id' => $user->getId(),
135
                    'service' => $provider,
136
                ]);
137
            }
138
        } catch (Exception) {
139
            return redirect(config('settings.clientBaseUrl').'/social-callback?token=&status=false&message=Something went wrong!');
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect(config('...Something went wrong!') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type App\Http\Controllers\Auth\JsonResponse.
Loading history...
140
        }
141
142
        if ($this->loggableSocialUser($curUser)) {
143
            Auth::guard('web')->login($curUser, true);
144
145
            return redirect(config('settings.clientBaseUrl').'/social-callback?token='.csrf_token().'&status=success&message=success');
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect(config('...ccess&message=success') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type App\Http\Controllers\Auth\JsonResponse.
Loading history...
146
        }
147
148
            return redirect(config('settings.clientBaseUrl').'/social-callback?token=&status=false&message=Something went wrong while we processing the login. Please try again!');
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect(config('...in. Please try again!') returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type App\Http\Controllers\Auth\JsonResponse.
Loading history...
149
    }
150
151
    public function needsToCreateSocial(User $user, $service)
152
    {
153
        return ! $user->hasSocialLinked($service);
154
    }
155
156
    public function unique_random($table, $col, $chars = 16)
0 ignored issues
show
Unused Code introduced by
The parameter $table is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

156
    public function unique_random(/** @scrutinizer ignore-unused */ $table, $col, $chars = 16)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
157
    {
158
        $unique = false;
159
160
        // Store tested results in array to not test them again
161
        $tested = [];
162
163
        do {
164
            // Generate random string of characters
165
            $random = Str::random($chars);
166
167
            // Check if it's already testing
168
            // If so, don't query the database again
169
            if (in_array($random, $tested)) {
170
                continue;
171
            }
172
173
            // Check if it is unique in the database
174
            $count = Company::where($col, '=', $random)->count();
175
176
            // Store the random character in the tested array
177
            // To keep track which ones are already tested
178
            $tested[] = $random;
179
180
            // String appears to be unique
181
            if ($count === 0) {
182
                // Set unique to true to break the loop
183
                $unique = true;
184
            }
185
186
            // If unique is still false at this point
187
            // it will just repeat all the steps until
188
            // it has generated a random string of characters
189
        } while (! $unique);
190
191
        return $random;
192
    }
193
194
    public function providerLogin(Request $request, $provider)
0 ignored issues
show
Unused Code introduced by
The parameter $provider is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

194
    public function providerLogin(Request $request, /** @scrutinizer ignore-unused */ $provider)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
195
    {
196
        $data = $request->all();
197
198
        return response()->json($data);
199
    }
200
201
    public function confirmSubscription(Request $request)
202
    {
203
        $request->all();
204
        $user = $this->loggableUser($request);
205
206
        return response()->json($user);
207
    }
208
209
    protected function attemptLogin(Request $request): bool
210
    {
211
        $this->user = $this->loggableUser($request);
212
213
        if (! $this->user) {
214
            return false;
215
        }
216
217
        if ($request->attributes->get('sanctum')) {
218
            Auth::guard('web')->login($this->user, $request->input('remember'));
219
        }
220
221
        Event::dispatch($this->user, $request->ip(), $request->header('User-Agent'));
222
223
        return true;
224
    }
225
226
    protected function sendLoginResponse(Request $request)
227
    {
228
        $this->clearLoginAttempts($request);
229
230
        if ($request->attributes->get('sanctum')) {
231
            $request->session()->regenerate();
232
233
            return [
234
                'auth' => Auth::check(),
235
                'csrfToken' => csrf_token(),
236
                'role_id' => Auth::user()->role_id,
0 ignored issues
show
Bug introduced by
Accessing role_id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
237
            ];
238
        }
239
240
        $token = $this->user->createToken($request->get('device_name'));
0 ignored issues
show
Bug introduced by
The method createToken() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

240
        /** @scrutinizer ignore-call */ 
241
        $token = $this->user->createToken($request->get('device_name'));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
241
242
        return response()->json(['token' => $token->plainTextToken])
243
            ->cookie('webview', true)
244
            ->cookie('Authorization', $token->plainTextToken);
245
    }
246
247
    protected function authenticated(Request $request, $user)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

247
    protected function authenticated(/** @scrutinizer ignore-unused */ Request $request, $user)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
248
    {
249
        return response()->json([
250
            'auth' => Auth::check(),
251
            'csrfToken' => csrf_token(),
252
            'role_id' => $user->role_id,
253
        ]);
254
    }
255
256
    protected function validateLogin(Request $request)
257
    {
258
        $attributes = [
259
            $this->username() => 'required|string',
260
            'password' => 'required|string',
261
        ];
262
263
        if (! $request->attributes->get('sanctum')) {
264
            $attributes['device_name'] = 'required|string';
265
        }
266
267
        $request->validate($attributes);
268
    }
269
270
    /**
271
     * @param  $provider
272
     * @return JsonResponse
273
     */
274
    protected function validateProvider($provider)
275
    {
276
        if (! in_array($provider, ['facebook', 'google', 'github'])) {
277
            return response()->json(['error' => 'Please login using facebook or google or github'], 422);
0 ignored issues
show
Bug Best Practice introduced by
The expression return response()->json(...oogle or github'), 422) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type App\Http\Controllers\Auth\JsonResponse.
Loading history...
278
        }
279
    }
280
281
    private function create_company($user)
282
    {
283
        $company_count = Company::count();
284
285
        $company = Company::create([
286
            'name' => $user->email.($company_count + 1),
287
            'email' => $user->email,
288
            // 'is_active' => 1,
289
            'is_tenant' => 1,
290
            'status' => 1,
291
        ]);
292
293
        $user->person->companies()->attach($company->id, ['person_id' => $user->person->id, 'is_main' => 1, 'is_mandatary' => 1, 'company_id' => $company->id]);
294
295
        /**            Tree::create([
296
         * 'name' => 'Default Tree',
297
         * 'description' => 'Automatically created tree as only tree remaining was deleted.',
298
         * 'user_id' => $user->id,
299
         * 'company_id' => $company->id,
300
         * ]);.
301
         */
302
        $company_id = $company->id;
0 ignored issues
show
Unused Code introduced by
The assignment to $company_id is dead and can be removed.
Loading history...
303
        //                \Log::debug('CreateDBs----------------------'.$company);
304
        CreateDBs::dispatch($company);
305
        //                \Log::debug('Migration----------------------'.$company);
306
        Migration::dispatch($company, $user->name, $user->email, $user->password);
307
    }
308
309
    private function loggableUser(Request $request)
310
    {
311
        $user = User::whereEmail($request->input('email'))->first();
312
313
        if (! optional($user)->currentPasswordIs($request->input('password'))) {
314
            return;
315
        }
316
317
        if (! $user->email) {
318
            throw ValidationException::withMessages([
319
                'email' => 'Email does not exist.',
320
            ]);
321
        }
322
323
        if ($user->passwordExpired()) {
324
            throw ValidationException::withMessages([
325
                'email' => 'Password expired. Please set a new one.',
326
            ]);
327
        }
328
        if ($user->isInactive()) {
329
            throw ValidationException::withMessages([
330
                'email' => 'Account disabled. Please contact the administrator.',
331
            ]);
332
        }
333
334
        if (! App::runningUnitTests()) {
335
            $company = $user->person->company();
336
            //            \Log::debug('Login----------------------'.$company);
337
            $tenant = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $tenant is dead and can be removed.
Loading history...
338
            if ($company) {
339
                $tenant = true;
340
            }
341
            // set company id as default
342
            $main_company = $user->person->company();
343
            if ($main_company !== null && ! $user->isAdmin()) {
344
                $c_id = $main_company->id;
0 ignored issues
show
Unused Code introduced by
The assignment to $c_id is dead and can be removed.
Loading history...
345
            }
346
            if (! $user->isAdmin()) {
347
                $tenants = Tenant::find($main_company->id);
348
            }
349
            if ($user->isAdmin()) {
350
                $tenants = null;
351
            }
352
            if ($main_company === null && ! $user->isAdmin()) {
353
                //   if (($main_company == null||$tenants=='') && ! $user->isAdmin()) {
354
                //   if ($main_company == null) {
355
                $this->create_company($user);
356
            } elseif ($tenants && ! $user->isAdmin()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tenants does not seem to be defined for all execution paths leading up to this point.
Loading history...
357
                //                    $c = DB::connection('tenantdb',$tenants->tenancy_db_name)->table('users')->count();
358
                $company = \App\Models\Company::find($main_company->id);
359
                //                    \Log::debug('Database----------------------'.$main_company->id);
360
                tenancy()->initialize($tenants);
361
                $tenants->run(function () use ($company, $user) {
362
                    //  $company->save();
363
                    $c = User::count();
364
                    if ($c === 0) {
365
                        //  \Log::debug('Run Migration----------------------');
366
                        return Migration::dispatch($company, $user->name, $user->email, $user->password);
367
                    }
368
                    // \Log::debug($company->id.-'users----------------------'.$c);
369
                });
370
                tenancy()->end();
371
                return $user;
372
            }
373
        }
374
375
        return $user;
376
    }
377
378
    private function loggableSocialUser($user): bool
379
    {
380
        $company = $user->person->company();
381
        $tenant = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $tenant is dead and can be removed.
Loading history...
382
383
        if ($company) {
384
            $tenant = true;
385
        }
386
        // set company id as default
387
        $main_company = $user->person->company();
388
        if ($main_company !== null && ! $user->isAdmin()) {
389
            $c_id = $main_company->id.$user->id;
0 ignored issues
show
Unused Code introduced by
The assignment to $c_id is dead and can be removed.
Loading history...
390
        }
391
392
        if ($main_company === null && ! $user->isAdmin()) {
393
            //          if ($main_company == null) {
394
            $this->create_company($user);
395
        }
396
397
        return true;
398
    }
399
}
400