Skip to content

Commit

Permalink
Extract common logic to ExternalAuthController
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaszkadziela committed Jun 19, 2024
1 parent 7355996 commit 7eaa8f2
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 187 deletions.
99 changes: 99 additions & 0 deletions app/Http/Controllers/ExternalAuth/ExternalAuthController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

namespace App\Http\Controllers\ExternalAuth;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\AccountCreatedViaProvider;
use App\Providers\RouteServiceProvider;
use App\View\Components\Notification;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;
use Throwable;

abstract class ExternalAuthController extends Controller
{
/**
* Redirect user to the provider's authorization page.
*/
public function redirect(): RedirectResponse
{
if (!config(Str::lower('services.' . $this->getProviderName() . '.enabled'))) {
Notification::push(
Lang::get('notifications.in-app.external-auth-failed.title'),
Lang::get('notifications.in-app.external-auth-failed.description', ['provider' => $this->getProviderName()]),
Notification::DANGER,
);

return redirect()->back();
}

return Socialite::driver($this->getProviderName())->redirect();
}

/**
* Process data retrieved from the provider.
*/
public function callback(): RedirectResponse
{
$externalUser = null;

try {
$externalUser = Socialite::driver($this->getProviderName())->user();

$user = User::where('email', '=', $externalUser->getEmail())->first();

if ($user === null) {
$password = Str::password(16);

$user = new User([
'username' => $externalUser->getNickname() ?? Str::before($externalUser->getEmail(), '@'),
'email' => $externalUser->getEmail(),
'password' => $password,
]);

$user->email_verified_at = Carbon::now();
$user->save();

$user->notify(new AccountCreatedViaProvider($this->getProviderName(), $user->email, $password));
}

Auth::login($user, true);

$notificationType = $user->wasRecentlyCreated ? 'registered' : 'logged-in';

Notification::push(
Lang::get('notifications.in-app.' . $notificationType . '.title'),
Lang::get('notifications.in-app.' . $notificationType . '.description', ['username' => $user->username]),
$notificationType === 'registered' ? Notification::SUCCESS : Notification::INFO,
);

return redirect(RouteServiceProvider::HOME);
} catch (Throwable $t) {
Notification::push(
Lang::get('notifications.in-app.external-auth-failed.title'),
Lang::get('notifications.in-app.external-auth-failed.description', ['provider' => $this->getProviderName()]),
Notification::DANGER,
);

Log::info(class_basename($this) . ': Authentication failed for ' . $this->getProviderName() . ' user ' . $externalUser?->getEmail() ?? request()->ip(), [
'code' => $t->getCode(),
'message' => $t->getMessage(),
'file' => $t->getFile(),
'line' => $t->getLine(),
]);
}

return redirect('/');
}

/**
* Get name of the Socialite provider.
*/
abstract protected function getProviderName(): string;
}
97 changes: 3 additions & 94 deletions app/Http/Controllers/ExternalAuth/FacebookAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,10 @@

namespace App\Http\Controllers\ExternalAuth;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\AccountCreatedViaProvider;
use App\Providers\RouteServiceProvider;
use App\View\Components\Notification;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;
use Throwable;

class FacebookAuthController extends Controller
class FacebookAuthController extends ExternalAuthController
{
public const PROVIDER = 'Facebook';

/**
* Redirect user to the provider's authorization page.
*/
public function redirect(): RedirectResponse
{
if (!config('services.facebook.enabled')) {
Notification::push(
Lang::get('notifications.in-app.external-auth-failed.title'),
Lang::get('notifications.in-app.external-auth-failed.description', ['provider' => self::PROVIDER]),
Notification::DANGER,
);

return redirect()->back();
}

return Socialite::driver(self::PROVIDER)->redirect();
}

/**
* Process data retrieved from the provider.
*/
public function callback(): RedirectResponse
protected function getProviderName(): string
{
$facebookUser = null;

try {
$facebookUser = Socialite::driver(self::PROVIDER)->user();

$user = User::where('email', '=', $facebookUser->getEmail())
->when(
!empty($facebookUser->getNickname()),
fn (Builder $query) => $query->orWhere('username', '=', $facebookUser->getNickname())
)
->first();

if ($user === null) {
$password = Str::password(16);

$user = new User([
'username' => $facebookUser->getNickname() ?? Str::before($facebookUser->getEmail(), '@'),
'email' => $facebookUser->getEmail(),
'password' => $password,
]);

$user->email_verified_at = Carbon::now();
$user->save();

$user->notify(new AccountCreatedViaProvider(self::PROVIDER, $user->email, $password));
}

Auth::login($user, true);

$notificationType = $user->wasRecentlyCreated ? 'registered' : 'logged-in';

Notification::push(
Lang::get('notifications.in-app.' . $notificationType . '.title'),
Lang::get('notifications.in-app.' . $notificationType . '.description', ['username' => $user->username]),
$notificationType === 'registered' ? Notification::SUCCESS : Notification::INFO,
);

return redirect(RouteServiceProvider::HOME);
} catch (Throwable $t) {
Notification::push(
Lang::get('notifications.in-app.external-auth-failed.title'),
Lang::get('notifications.in-app.external-auth-failed.description', ['provider' => self::PROVIDER]),
Notification::DANGER,
);

Log::info(class_basename($this) . ': Authentication failed for ' . self::PROVIDER . ' user ' . $facebookUser?->getEmail() ?? request()->ip(), [
'code' => $t->getCode(),
'message' => $t->getMessage(),
'file' => $t->getFile(),
'line' => $t->getLine(),
]);
}

return redirect('/');
return 'Facebook';
}
}
96 changes: 3 additions & 93 deletions app/Http/Controllers/ExternalAuth/GoogleAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,100 +2,10 @@

namespace App\Http\Controllers\ExternalAuth;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\AccountCreatedViaProvider;
use App\Providers\RouteServiceProvider;
use App\View\Components\Notification;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;
use Throwable;

class GoogleAuthController extends Controller
class GoogleAuthController extends ExternalAuthController
{
public const PROVIDER = 'Google';

/**
* Redirect user to the provider's authorization page.
*/
public function redirect(): RedirectResponse
protected function getProviderName(): string
{
if (!config('services.google.enabled')) {
Notification::push(
Lang::get('notifications.in-app.external-auth-failed.title'),
Lang::get('notifications.in-app.external-auth-failed.description', ['provider' => self::PROVIDER]),
Notification::DANGER,
);

return redirect()->back();
}

return Socialite::driver(self::PROVIDER)->redirect();
}

/**
* Process data retrieved from the provider.
*/
public function callback(): RedirectResponse
{
$googleUser = null;

try {
$googleUser = Socialite::driver(self::PROVIDER)->user();
$user = User::where('email', '=', $googleUser->getEmail())
->when(
!empty($googleUser->getNickname()),
fn (Builder $query) => $query->orWhere('username', '=', $googleUser->getNickname())
)
->first();

if ($user === null) {
$password = Str::password(16);

$user = new User([
'username' => $googleUser->getNickname() ?? Str::before($googleUser->getEmail(), '@'),
'email' => $googleUser->getEmail(),
'password' => $password,
]);

$user->email_verified_at = Carbon::now();
$user->save();

$user->notify(new AccountCreatedViaProvider(self::PROVIDER, $user->email, $password));
}

Auth::login($user, true);

$notificationType = $user->wasRecentlyCreated ? 'registered' : 'logged-in';

Notification::push(
Lang::get('notifications.in-app.' . $notificationType . '.title'),
Lang::get('notifications.in-app.' . $notificationType . '.description', ['username' => $user->username]),
$notificationType === 'registered' ? Notification::SUCCESS : Notification::INFO,
);

return redirect(RouteServiceProvider::HOME);
} catch (Throwable $t) {
Notification::push(
Lang::get('notifications.in-app.external-auth-failed.title'),
Lang::get('notifications.in-app.external-auth-failed.description', ['provider' => self::PROVIDER]),
Notification::DANGER,
);

Log::info(class_basename($this) . ': Authentication failed for ' . self::PROVIDER . ' user ' . $googleUser?->getEmail() ?? request()->ip(), [
'code' => $t->getCode(),
'message' => $t->getMessage(),
'file' => $t->getFile(),
'line' => $t->getLine(),
]);
}

return redirect('/');
return 'Google';
}
}

0 comments on commit 7eaa8f2

Please sign in to comment.