diff --git a/app/Http/Controllers/Auth/SocialLoginController.php b/app/Http/Controllers/Auth/SocialLoginController.php index f2f9492..76263bc 100644 --- a/app/Http/Controllers/Auth/SocialLoginController.php +++ b/app/Http/Controllers/Auth/SocialLoginController.php @@ -2,11 +2,20 @@ namespace App\Http\Controllers\Auth; +use App\Models\AccountOauth; +use Illuminate\Http\Request; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; -use App\Http\Controllers\Controller; - +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Mail; use Socialite; +use App\Http\Controllers\Controller; +use App\Mail\SocialLink; +use App\Models\Oauth; +use App\User; +use function App\Console\Commands\object_to_array; + class SocialLoginController extends Controller { public function redirectToProvider($provider) @@ -18,16 +27,97 @@ class SocialLoginController extends Controller { $openiduser = Socialite::with($provider)->user(); - $user = Socialite::with($provider)->findOrCreateUser($openiduser); + $oo = Oauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]); - Auth::login($user,FALSE); + // See if this user has connected and linked previously + $aoo = $oo->accounts->where('userid',$openiduser->id); - /* - if (! $user->profile_update) + if ($aoo->count() == 1) { - return redirect()->to(url('settings')); + $aoo = $aoo->first(); + + if ((is_null($user=$aoo->user) AND (is_null($aoo->account) OR is_null($user=$aoo->account->user))) OR ! $user->active) + { + if (! $user) { + $user = User::where('email',$openiduser->email)->first(); + } + + if (! $user OR ! $user->active) + { + return redirect('/login')->with('error','Invalid account, or account inactive, please contact an admin.'); + } + + return $this->link($provider,$aoo,$user); + } + + // All Set to login + Auth::login($user,FALSE); + + // If there are too many users, then we have a problem + } elseif ($aoo->count() > 1) { + return redirect('/login')->with('error','Seems you have multiple oauth IDs, please contact an admin.'); + + // User is using OAUTH for the first time. + } else { + $uo = User::active()->where('email',$openiduser->email); + + // See if their is an account with this email address + if ($uo->count() == 1) + { + $aoo = new AccountOauth; + $aoo->userid = $openiduser->id; + $aoo->oauth_data = $openiduser->user; + $oo->accounts()->save($aoo); + + return $this->link($provider,$aoo,$uo->first()); + + // If there are too many users, then we have a problem + } elseif ($uo->count() > 1) { + return redirect('/login')->with('error','Seems you have multiple accounts, please contact an admin.'); + + } else { + return redirect('/login')->with('error','Seems you dont have an account with that email, please contact an admin.'); + } } - */ + + return redirect()->intended(); + } + + /** + * We have identified the user and oauth, just need them to confirm the link + * + * @param $provider + * @param User $uo + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function link($provider,AccountOauth $ao,User $uo) + { + Mail::to($uo->email)->send(new SocialLink($ao)); + + return view('auth.social_link') + ->with('oauthid',$ao->id) + ->with('provider',$provider); + } + + public function linkcomplete(Request $request,$provider) + { + // Load our oauth id + $aoo = AccountOauth::findOrFail($request->post('oauthid')); + + // Check our email matches + if (Arr::get($aoo->oauth_data,'email','invalid') !== $request->post('email')) + return redirect('/login')->with('error','Account details didnt match to make link.'); + + // Check our token matches + if ($aoo->link_token !== $request->post('token')) + return redirect('/login')->with('error','Token details didnt match to make link.'); + + // Load our email. + $uo = User::where('email',$request->post('email'))->firstOrFail(); + + $aoo->user_id = $uo->id; + $aoo->save(); + Auth::login($uo,FALSE); return redirect()->intended(); } diff --git a/app/Mail/OrderRequest.php b/app/Mail/OrderRequest.php index 737cd05..90f1466 100644 --- a/app/Mail/OrderRequest.php +++ b/app/Mail/OrderRequest.php @@ -35,12 +35,12 @@ class OrderRequest extends Mailable */ public function build() { - switch ($this->service->category) + switch (get_class($this->service->type)) { - case 'ADSL': $subject = sprintf('%s: %s',$this->service->category,$this->service->service_adsl->service_address); + case 'App\Models\Service\Adsl': $subject = sprintf('NBN: %s',$this->service->type->service_address); break; - case 'VOIP': $subject = sprintf('%s: %s',$this->service->category,$this->service->service_voip->service_number); + case 'App\Models\Service\Voip': $subject = sprintf('VOIP: %s',$this->service->type->service_number); break; default: diff --git a/app/Mail/SocialLink.php b/app/Mail/SocialLink.php new file mode 100644 index 0000000..8e2b264 --- /dev/null +++ b/app/Mail/SocialLink.php @@ -0,0 +1,43 @@ +token = $o->link_token; + $this->user = $o; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this + ->markdown('email.system.social_link') + ->subject('Link your Account') + ->with(['site'=>$this->user->site]); + } +} \ No newline at end of file diff --git a/app/Models/AccountOauth.php b/app/Models/AccountOauth.php new file mode 100644 index 0000000..bb2d737 --- /dev/null +++ b/app/Models/AccountOauth.php @@ -0,0 +1,47 @@ +'array', + ]; + + public function account() + { + return $this->belongsTo(Account::class); + } + + public function site() + { + return $this->belongsTo(Site::class); + } + + public function User() + { + return $this->belongsTo(User::class); + } + + /** + * Get a link token to use when validating account. + */ + public function getLinkTokenAttribute() + { + return strtoupper(substr(md5($this->id.$this->date_last),0,8)); + } +} \ No newline at end of file diff --git a/app/Models/Oauth.php b/app/Models/Oauth.php new file mode 100644 index 0000000..5a43f33 --- /dev/null +++ b/app/Models/Oauth.php @@ -0,0 +1,25 @@ +hasMany(AccountOauth::class); + } +} \ No newline at end of file diff --git a/app/Traits/NextKey.php b/app/Traits/NextKey.php index 7133159..bc5714f 100644 --- a/app/Traits/NextKey.php +++ b/app/Traits/NextKey.php @@ -18,6 +18,9 @@ trait NextKey static::creating(function($model) { $model->id = self::NextId(); + + if (! $model->site_id) + $model->site_id = config('SITE_SETUP')->id; }); static::saved(function($model) diff --git a/app/User.php b/app/User.php index a60f6c7..b9677ae 100644 --- a/app/User.php +++ b/app/User.php @@ -2,6 +2,7 @@ namespace App; +use App\Models\Site; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Laravel\Passport\HasApiTokens; @@ -82,6 +83,11 @@ class User extends Authenticatable return $this->hasManyThrough(Models\Payment::class,Models\Account::class); } + public function site() + { + return $this->belongsTo(Site::class); + } + public function services() { return $this->hasManyThrough(Models\Service::class,Models\Account::class); diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore old mode 100755 new mode 100644 diff --git a/composer.lock b/composer.lock index f7cf043..889ef72 100644 --- a/composer.lock +++ b/composer.lock @@ -2357,11 +2357,11 @@ }, { "name": "leenooks/laravel", - "version": "0.3.10", + "version": "0.3.12", "source": { "type": "git", "url": "https://dev.leenooks.net/leenooks/laravel", - "reference": "1efdfca55f77c3a473b5009a5abca11f8cbd97b1" + "reference": "a946ce44185a21abd28c56981b55867201c403e9" }, "require": { "acacha/user": "^0.2.2", @@ -2399,7 +2399,7 @@ "laravel", "leenooks" ], - "time": "2019-07-03T07:16:46+00:00" + "time": "2019-09-03T04:37:52+00:00" }, { "name": "maximebf/debugbar", diff --git a/config/app.php b/config/app.php index 456e588..979b205 100644 --- a/config/app.php +++ b/config/app.php @@ -174,6 +174,7 @@ return [ // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, + Laravel\Socialite\SocialiteServiceProvider::class, /* * Other Service Providers... @@ -233,6 +234,7 @@ return [ 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'SnappyImage' => Barryvdh\Snappy\Facades\SnappyImage::class, + 'Socialite' => Laravel\Socialite\Facades\Socialite::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'Str' => Illuminate\Support\Str::class, 'URL' => Illuminate\Support\Facades\URL::class, diff --git a/config/auth.php b/config/auth.php index f8a1194..4dfb951 100644 --- a/config/auth.php +++ b/config/auth.php @@ -99,4 +99,12 @@ return [ ], ], + 'social' => [ + 'google' => [ + 'name' => 'Google', + 'id' => 'google', + 'class' => 'danger', + 'icon' => 'google', + ], + ], ]; diff --git a/config/services.php b/config/services.php index ef1f130..439a339 100644 --- a/config/services.php +++ b/config/services.php @@ -44,10 +44,16 @@ return [ ], ], - 'ezypay' => [ - 'plugin' => 'DD_EZYPAY', - 'base_uri' => 'https://api.ezypay.com/api/v1/', - 'token_user' => env('EZYPAY_TOKEN'), - 'guid' => env('EZYPAY_GUID'), - ], + 'ezypay' => [ + 'plugin' => 'DD_EZYPAY', + 'base_uri' => 'https://api.ezypay.com/api/v1/', + 'token_user' => env('EZYPAY_TOKEN'), + 'guid' => env('EZYPAY_GUID'), + ], + + 'google' => [ + 'client_id' => env('AUTH_GOOGLE_CLIENT_ID'), + 'client_secret' => env('AUTH_GOOGLE_SECRET'), + 'redirect' => '/auth/google/callback', + ], ]; diff --git a/database/migrations/2019_07_05_092048_add_user_to_accountoauth.php b/database/migrations/2019_07_05_092048_add_user_to_accountoauth.php new file mode 100644 index 0000000..84182ba --- /dev/null +++ b/database/migrations/2019_07_05_092048_add_user_to_accountoauth.php @@ -0,0 +1,70 @@ +index(['id','site_id'],'site_user_id_idx'); + }); + + Schema::table('ab_account_oauth', function (Blueprint $table) { + $table->dropPrimary(['id','site_id','account_id','oauth_id']); + $table->primary(['id','site_id','oauth_id']); + }); + + Schema::table('ab_account_oauth', function (Blueprint $table) { + $table->bigInteger('account_id')->nullable()->change(); + + $table->integer('user_id')->unsigned()->nullable(); + $table->unique(['site_id','user_id','oauth_id']); + $table->index(['user_id','site_id'],'site_user_id_idx'); + $table->foreign(['user_id','site_id'],'site_user_id')->references(['id','site_id'])->on('users'); + }); + + Schema::table('ab_oauth', function (Blueprint $table) { + $table->string('name',32)->change(); + $table->unique(['site_id','name']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('ab_account_oauth', function (Blueprint $table) { + $table->dropPrimary(['id','site_id','oauth_id']); + $table->primary(['id','site_id','account_id','oauth_id']); + }); + + Schema::table('ab_account_oauth', function (Blueprint $table) { + $table->dropForeign('site_user_id'); + $table->dropUnique(['site_id','user_id','oauth_id']); + $table->dropIndex('site_user_id_idx'); + $table->dropColumn('user_id'); + + $table->bigInteger('account_id')->change(); + }); + + Schema::table('users',function(Blueprint $table) { + $table->dropIndex('site_user_id_idx'); + }); + + Schema::table('ab_oauth', function (Blueprint $table) { + $table->string('name',32)->nullable()->change(); + $table->dropUnique(['site_id','name']); + }); + } +} diff --git a/resources/theme/backend/adminlte/auth/social_link.blade.php b/resources/theme/backend/adminlte/auth/social_link.blade.php new file mode 100644 index 0000000..61f48ed --- /dev/null +++ b/resources/theme/backend/adminlte/auth/social_link.blade.php @@ -0,0 +1,80 @@ +@extends('adminlte::layouts.auth') + +@section('htmlheader_title') + Link Account +@endsection + +@section('content') +
+ + +
+ NOTE: Link your account.

+ +
+ + @if (count($errors) > 0) +
+ Whoops! {{ trans('adminlte_lang::message.someproblems') }}

+ +
+ @endif + + +
+ + +
+
+ +@endsection \ No newline at end of file diff --git a/resources/theme/frontend/metronic/layouts/partials/mainheader.blade.php b/resources/theme/frontend/metronic/layouts/partials/mainheader.blade.php index 2439fed..65452fe 100644 --- a/resources/theme/frontend/metronic/layouts/partials/mainheader.blade.php +++ b/resources/theme/frontend/metronic/layouts/partials/mainheader.blade.php @@ -14,7 +14,7 @@
diff --git a/resources/views/email/system/social_link.blade.php b/resources/views/email/system/social_link.blade.php new file mode 100644 index 0000000..d45c57a --- /dev/null +++ b/resources/views/email/system/social_link.blade.php @@ -0,0 +1,18 @@ +@component('mail::message',['site'=>$site]) +Howdy, + +A request was made to link your account to a social login. + +If you didnt make this request, you can ignore this, and the request will be ignored. + +If you did make the request, then please enter the code displayed below. + +@component('mail::panel') + {{ $token }} +@endcomponent + +Once you've keyed in this code, you'll be able to login to your account using your social login instead of a username and a password. + +Thanks,
+{{ config('app.name') }} +@endcomponent \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 0926547..142351e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,6 +14,13 @@ Auth::routes(); Route::get('/logout','Auth\LoginController@logout'); +Route::group(['middleware'=>['theme:adminlte-be']],function() { + Route::get('auth/{socialProvider}', 'Auth\SocialLoginController@redirectToProvider'); + Route::get('auth/{socialProvider}/callback', 'Auth\SocialLoginController@handleProviderCallback'); + Route::get('auth/{socialProvider}/link', 'Auth\SocialLoginController@link'); + Route::post('auth/{socialProvider}/linkcomplete', 'Auth\SocialLoginController@linkcomplete'); +}); + // Generic Image Renderer - Render images that we dont have with a generic image Route::get('image/generic/{width}/{height}/{color}/{name?}','MediaController@image')->name('image');