Skip to content

Commit

Permalink
Refactor social login, ensure avatars, names are updated, use local a…
Browse files Browse the repository at this point in the history
…vatar storage
  • Loading branch information
mrcage committed Sep 21, 2022
1 parent 1c9676f commit 040a37e
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 25 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## NEXT

* Added support for specifying email domain for Google Oauth login
* Store avatar images locally

## 3.9.0

Expand Down
70 changes: 52 additions & 18 deletions app/Http/Controllers/Auth/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Socialite;

class LoginController extends Controller
Expand Down Expand Up @@ -174,7 +176,7 @@ public function redirectToProvider(string $driver)
public function handleProviderCallback(string $driver)
{
try {
$user = Socialite::driver($driver)->user();
$socialUser = Socialite::driver($driver)->user();
} catch (Exception $e) {
Log::error('Socialite login with driver '.$driver.' failed. '.$e->getMessage());

Expand All @@ -187,7 +189,7 @@ public function handleProviderCallback(string $driver)

if ($driver == 'google') {
$orgDomain = config('services.google.organization_domain');
if (filled($orgDomain) && ! str_ends_with($user->getEmail(), "@$orgDomain")) {
if (filled($orgDomain) && ! str_ends_with($socialUser->getEmail(), "@$orgDomain")) {
return redirect()
->route('login')
->with('error', __('Only email addresses of the organization :domain are accepted.', [
Expand All @@ -196,21 +198,32 @@ public function handleProviderCallback(string $driver)
}
}

// check if they're an existing user
$existingUser = User::where('email', $user->getEmail())->first();
if ($existingUser) {
auth()->login($existingUser, true);
} else {
$newUser = new User();
$newUser->provider_name = $driver;
$newUser->provider_id = $user->getId();
$newUser->name = $user->getName();
$newUser->email = $user->getEmail();
$newUser->email_verified_at = now();
$newUser->avatar = $user->getAvatar();
$newUser->locale = \App::getLocale();
$newUser->save();
/** @var User $user */
$user = User::firstOrCreate(
['email' => $socialUser->getEmail()],
[
'name' => $socialUser->getName(),
'password' => Str::random(32),
'provider_name' => $driver,
'provider_id' => $socialUser->getId(),
'locale' => \App::getLocale(),
]
);

// Update name, avatar in case they have changed on the provider side
$user->name = $socialUser->getName();
$user->avatar = $this->getAvatar($socialUser->getAvatar(), $user->avatar);

// Mark email as verified
if ($user->email_verified_at == null) {
$user->email_verified_at = now();
}

if ($user->isDirty()) {
$user->save();
}

if ($user->wasRecentlyCreated) {
Log::info('New user registered with Oauth provider.', [
'user_id' => $user->id,
'user_name' => $user->name,
Expand All @@ -219,10 +232,12 @@ public function handleProviderCallback(string $driver)
'client_ip' => request()->ip(),
]);

event(new UserSelfRegistered($newUser));
event(new UserSelfRegistered($user));
}

auth()->login($newUser, true);
Auth::login($user);

if ($user->wasRecentlyCreated) {
session()->flash('login_message', __('Hello :name. Thanks for registering with :app_name. Your account has been created, and the administrator has been informed, in order to grand you the appropriate permissions.', [
'name' => Auth::user()->name,
'app_name' => config('app.name'),
Expand All @@ -233,4 +248,23 @@ public function handleProviderCallback(string $driver)

return redirect($this->redirectPath());
}

private function getAvatar(?string $newAvatar, ?string $currentAvatar): ?string
{
if ($newAvatar === null) {
return null;
}

if (! ini_get('allow_url_fopen')) {
return $newAvatar;
}

$avatar = 'public/avatars/'.basename($newAvatar);
if ($currentAvatar !== null && $avatar != $currentAvatar && Storage::exists($currentAvatar)) {
Storage::delete($currentAvatar);
}
Storage::put($avatar, file_get_contents($newAvatar));

return $avatar;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public function index()

return response()->json([
'user' => $user,
'avatar_url' => $user->avatarUrl(),
'languages' => language()->allowed(),
'locale' => App::getLocale(),
'can_delete' => ! ($user->is_super_admin && User::where('is_super_admin', true)->count() == 1),
Expand Down
1 change: 0 additions & 1 deletion app/Http/Resources/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public function toArray($request)
'locale' => $this->locale,
'is_super_admin' => $this->is_super_admin,
'is_2fa_enabled' => $this->tfa_secret !== null,
'avatar' => $this->avatar,
'avatar_url' => $this->avatarUrl(),
'provider_name' => $this->provider_name,
'created_at' => $this->created_at,
Expand Down
15 changes: 12 additions & 3 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Storage;

class User extends Authenticatable implements HasLocalePreference
{
Expand All @@ -30,6 +31,8 @@ class User extends Authenticatable implements HasLocalePreference
'password',
'is_super_admin',
'locale',
'provider_name',
'provider_id',
];

/**
Expand Down Expand Up @@ -124,9 +127,15 @@ public function permissions(): Collection

public function avatarUrl(?int $size = null): string
{
return $this->avatar !== null
? $this->avatar
: route('users.avatar', [$this, 'size' => $size]);
if (blank($this->avatar)) {
return route('users.avatar', [$this, 'size' => $size]);
}

if (filter_var($this->avatar, FILTER_VALIDATE_URL)) {
return $this->avatar;
}

return Storage::url($this->avatar);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion resources/js/pages/users/UserIndexPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<template v-slot:cell(avatar_url)="data">
<UserAvatar
:value="data.item.name"
:src="data.item.avatar"
:src="data.item.avatar_url"
:badge-icon="data.item.is_super_admin ? 'shield-alt' : null"
/>
</template>
Expand Down
4 changes: 3 additions & 1 deletion resources/js/pages/users/UserProfilePage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<b-col cols="auto">
<UserAvatar
:value="user.name"
:src="user.avatar"
:src="avatar_url"
size="4em"
/>
</b-col>
Expand Down Expand Up @@ -107,6 +107,7 @@ export default {
isBusy: false,
errorText: null,
canDelete: false,
avatar_url: null,
}
},
computed: {
Expand All @@ -123,6 +124,7 @@ export default {
try {
let data = await userprofileApi.list()
this.user = data.user
this.avatar_url = data.avatar_url
this.languages = data.languages
this.canDelete = data.can_delete
} catch (err) {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/pages/users/UserShowPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<b-col cols="auto">
<UserAvatar
:value="user.name"
:src="user.avatar"
:src="user.avatar_url"
size="4em"
/>
</b-col>
Expand Down

0 comments on commit 040a37e

Please sign in to comment.