#2 - wip
This commit is contained in:
parent
197e7da9cc
commit
38af769f7b
@ -6,9 +6,9 @@ namespace Toby\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\Auth\Factory as AuthFactory;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Toby\Models\User;
|
||||
use Laravel\Socialite\SocialiteManager;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Toby\Models\User;
|
||||
|
||||
class GoogleController extends Controller
|
||||
{
|
||||
@ -29,8 +29,6 @@ class GoogleController extends Controller
|
||||
|
||||
$auth->guard()->login($user, true);
|
||||
|
||||
$user->syncGoogleData($socialUser);
|
||||
|
||||
return redirect()->route("dashboard");
|
||||
} catch (ModelNotFoundException) {
|
||||
return redirect()
|
||||
|
22
app/Http/Controllers/LogoutController.php
Normal file
22
app/Http/Controllers/LogoutController.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
class LogoutController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request): RedirectResponse
|
||||
{
|
||||
Auth::logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return redirect()->route("login");
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ namespace Toby\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Middleware;
|
||||
use Toby\Http\Resources\UserResource;
|
||||
|
||||
class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
@ -15,12 +16,7 @@ class HandleInertiaRequests extends Middleware
|
||||
|
||||
return array_merge(parent::share($request), [
|
||||
"auth" => fn() => [
|
||||
"user" => $user ? [
|
||||
"name" => $user->name,
|
||||
"email" => $user->email,
|
||||
"role" => "Human Resources Manager",
|
||||
"imageUrl" => $user->avatar,
|
||||
] : null,
|
||||
"user" => $user ? new UserResource($user) : null,
|
||||
],
|
||||
"flash" => fn() => [
|
||||
"success" => $request->session()->get("success"),
|
||||
|
21
app/Http/Resources/UserResource.php
Normal file
21
app/Http/Resources/UserResource.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserResource extends JsonResource
|
||||
{
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
"id" => $this->id,
|
||||
"name" => $this->name,
|
||||
"email" => $this->email,
|
||||
"role" => "Human Resources Manager",
|
||||
"avatar" => "https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80",
|
||||
];
|
||||
}
|
||||
}
|
@ -7,14 +7,11 @@ namespace Toby\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Socialite\Two\User as SocialUser;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $email
|
||||
* @property string $avatar
|
||||
* @property string $google_id
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
@ -29,17 +26,4 @@ class User extends Authenticatable
|
||||
protected $hidden = [
|
||||
"remember_token",
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
"email_verified_at" => "datetime",
|
||||
];
|
||||
|
||||
public function syncGoogleData(SocialUser $user): void
|
||||
{
|
||||
$this->name = $user->getName();
|
||||
$this->avatar = $user->getAvatar();
|
||||
$this->google_id = $user->getId();
|
||||
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
1353
composer.lock
generated
1353
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -12,9 +12,7 @@ return new class() extends Migration {
|
||||
Schema::create("users", function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string("name");
|
||||
$table->string("avatar")->nullable();
|
||||
$table->string("email")->unique();
|
||||
$table->string("google_id")->nullable();
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
60
package-lock.json
generated
60
package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "application",
|
||||
"name": "toby",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
@ -11,15 +11,15 @@
|
||||
"@inertiajs/inertia-vue3": "^0.6.0",
|
||||
"@inertiajs/progress": "^0.2.7",
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"@tailwindcss/line-clamp": "^0.3.0",
|
||||
"@tailwindcss/line-clamp": "^0.3.1",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@vue/compiler-sfc": "^3.2.26",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"postcss": "^8.4.5",
|
||||
"tailwindcss": "^3.0.12",
|
||||
"tailwindcss": "^3.0.13",
|
||||
"vue": "^3.2.26",
|
||||
"vue-loader": "^16.8.3"
|
||||
"vue-loader": "^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.6.0",
|
||||
@ -1782,9 +1782,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/line-clamp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.3.0.tgz",
|
||||
"integrity": "sha512-ffDDclrqr3sy8cpChCozedDUAN8enxqAiWeH8d4dGQ2hcXlxf51+7KleveFi/n/TxEuRVApoL7hICeDOdYPKpg==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.3.1.tgz",
|
||||
"integrity": "sha512-pNr0T8LAc3TUx/gxCfQZRe9NB2dPEo/cedPHzUGIPxqDMhgjwNm6jYxww4W5l0zAsAddxr+XfZcqttGiFDgrGg==",
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1"
|
||||
}
|
||||
@ -4166,9 +4166,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.2.0.tgz",
|
||||
"integrity": "sha512-cLIdTuOAMXyHeQ4drYKcZfoyzdwdBpH279X8/N0DgmotEI9yFKb5O/cAgoie/CkQZCH/MOmh0xw/KEfS90zY2A==",
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.3.0.tgz",
|
||||
"integrity": "sha512-IIuLHw4vQxGlHcoP2dG6t/2OVdQf2qoyAzEGAxreU1afZOHGA7y3TWq8I+r3ZA6Wjs6xpeUWGHlT31QGr9Rb5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
@ -8451,9 +8451,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.0.12",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.12.tgz",
|
||||
"integrity": "sha512-VqhF86z2c34sJyS5ZS8Q2nYuN0KzqZw1GGsuQQO9kJ3mY1oG7Fsag0vICkxUVXk6P+1sUkTkjMjKWCjEF0hNHw==",
|
||||
"version": "3.0.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.13.tgz",
|
||||
"integrity": "sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==",
|
||||
"dependencies": {
|
||||
"arg": "^5.0.1",
|
||||
"chalk": "^4.1.2",
|
||||
@ -8474,7 +8474,7 @@
|
||||
"postcss-selector-parser": "^6.0.8",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"quick-lru": "^5.1.1",
|
||||
"resolve": "^1.20.0"
|
||||
"resolve": "^1.21.0"
|
||||
},
|
||||
"bin": {
|
||||
"tailwind": "lib/cli.js",
|
||||
@ -8893,9 +8893,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader": {
|
||||
"version": "16.8.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
||||
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz",
|
||||
"integrity": "sha512-OWSXjrzIvbF2LtOUmxT3HYgwwubbfFelN8PAP9R9dwpIkj48TVioHhWWSx7W7fk+iF5cgg3CBJRxwTdtLU4Ecg==",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
@ -10639,9 +10639,9 @@
|
||||
}
|
||||
},
|
||||
"@tailwindcss/line-clamp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.3.0.tgz",
|
||||
"integrity": "sha512-ffDDclrqr3sy8cpChCozedDUAN8enxqAiWeH8d4dGQ2hcXlxf51+7KleveFi/n/TxEuRVApoL7hICeDOdYPKpg==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.3.1.tgz",
|
||||
"integrity": "sha512-pNr0T8LAc3TUx/gxCfQZRe9NB2dPEo/cedPHzUGIPxqDMhgjwNm6jYxww4W5l0zAsAddxr+XfZcqttGiFDgrGg==",
|
||||
"requires": {}
|
||||
},
|
||||
"@tailwindcss/typography": {
|
||||
@ -12614,9 +12614,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-vue": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.2.0.tgz",
|
||||
"integrity": "sha512-cLIdTuOAMXyHeQ4drYKcZfoyzdwdBpH279X8/N0DgmotEI9yFKb5O/cAgoie/CkQZCH/MOmh0xw/KEfS90zY2A==",
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.3.0.tgz",
|
||||
"integrity": "sha512-IIuLHw4vQxGlHcoP2dG6t/2OVdQf2qoyAzEGAxreU1afZOHGA7y3TWq8I+r3ZA6Wjs6xpeUWGHlT31QGr9Rb5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
@ -15646,9 +15646,9 @@
|
||||
}
|
||||
},
|
||||
"tailwindcss": {
|
||||
"version": "3.0.12",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.12.tgz",
|
||||
"integrity": "sha512-VqhF86z2c34sJyS5ZS8Q2nYuN0KzqZw1GGsuQQO9kJ3mY1oG7Fsag0vICkxUVXk6P+1sUkTkjMjKWCjEF0hNHw==",
|
||||
"version": "3.0.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.13.tgz",
|
||||
"integrity": "sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==",
|
||||
"requires": {
|
||||
"arg": "^5.0.1",
|
||||
"chalk": "^4.1.2",
|
||||
@ -15669,7 +15669,7 @@
|
||||
"postcss-selector-parser": "^6.0.8",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"quick-lru": "^5.1.1",
|
||||
"resolve": "^1.20.0"
|
||||
"resolve": "^1.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob-parent": {
|
||||
@ -15971,9 +15971,9 @@
|
||||
}
|
||||
},
|
||||
"vue-loader": {
|
||||
"version": "16.8.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
||||
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.0.0.tgz",
|
||||
"integrity": "sha512-OWSXjrzIvbF2LtOUmxT3HYgwwubbfFelN8PAP9R9dwpIkj48TVioHhWWSx7W7fk+iF5cgg3CBJRxwTdtLU4Ecg==",
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
|
@ -18,15 +18,15 @@
|
||||
"@inertiajs/inertia-vue3": "^0.6.0",
|
||||
"@inertiajs/progress": "^0.2.7",
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"@tailwindcss/line-clamp": "^0.3.0",
|
||||
"@tailwindcss/line-clamp": "^0.3.1",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@vue/compiler-sfc": "^3.2.26",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"postcss": "^8.4.5",
|
||||
"tailwindcss": "^3.0.12",
|
||||
"tailwindcss": "^3.0.13",
|
||||
"vue": "^3.2.26",
|
||||
"vue-loader": "^16.8.3"
|
||||
"vue-loader": "^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.6.0",
|
||||
|
@ -22,7 +22,7 @@
|
||||
<server name="APP_KEY" value="base64:SKEJSy9oF9chQBCMbxqgj5zhtAvug9kwZ+cDiP1Y8A8="/>
|
||||
<server name="BCRYPT_ROUNDS" value="4"/>
|
||||
<server name="CACHE_DRIVER" value="array"/>
|
||||
<server name="DB_CONNECTION" value="sqlite"/>
|
||||
<server name="DB_CONNECTION" value="testing"/>
|
||||
<server name="DB_DATABASE" value=":memory:"/>
|
||||
<server name="MAIL_MAILER" value="array"/>
|
||||
<server name="QUEUE_CONNECTION" value="sync"/>
|
||||
|
BIN
public/img/icon.png
Normal file
BIN
public/img/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
public/img/logo.png
Normal file
BIN
public/img/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
@ -18,7 +18,7 @@
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="mx-auto h-20 w-20 rounded-full"
|
||||
:src="user.imageUrl"
|
||||
:src="user.avatar"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
|
@ -42,7 +42,7 @@
|
||||
<span class="sr-only">Open user menu</span>
|
||||
<img
|
||||
class="h-8 w-8 rounded-full"
|
||||
:src="user.imageUrl"
|
||||
:src="user.avatar"
|
||||
alt=""
|
||||
>
|
||||
</MenuButton>
|
||||
@ -62,7 +62,9 @@
|
||||
>
|
||||
<InertiaLink
|
||||
:href="item.href"
|
||||
:class="[active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700']"
|
||||
:method="item.method"
|
||||
:as="item.as"
|
||||
:class="[active ? 'bg-gray-100' : '', 'block w-full text-left px-4 py-2 text-sm text-gray-700']"
|
||||
>
|
||||
{{ item.name }}
|
||||
</InertiaLink>
|
||||
@ -209,8 +211,10 @@
|
||||
<InertiaLink
|
||||
v-for="item in userNavigation"
|
||||
:key="item.name"
|
||||
:method="item.method"
|
||||
:as="item.as"
|
||||
:href="item.href"
|
||||
class="block rounded-md px-3 py-2 text-base text-gray-900 font-medium hover:bg-gray-100 hover:text-gray-800"
|
||||
class="block w-full text-left rounded-md px-3 py-2 text-base text-gray-900 font-medium hover:bg-gray-100 hover:text-gray-800"
|
||||
>
|
||||
{{ item.name }}
|
||||
</InertiaLink>
|
||||
@ -270,7 +274,7 @@ export default {
|
||||
const userNavigation = [
|
||||
{name: 'Your Profile', href: '#'},
|
||||
{name: 'Settings', href: '#'},
|
||||
{name: 'Sign out', href: '#'},
|
||||
{name: 'Sign out', href: '/logout', method: 'post', as: 'button'},
|
||||
];
|
||||
|
||||
return {
|
||||
|
@ -2,29 +2,19 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Toby\Http\Controllers\GoogleController;
|
||||
use Toby\Http\Controllers\LogoutController;
|
||||
|
||||
Route::middleware("auth")->group(function (): void {
|
||||
Route::get("/", fn() => inertia("Dashboard"))->name("dashboard");
|
||||
Route::get("/logout", function (Request $request) {
|
||||
Auth::logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
|
||||
return redirect()->route("login");
|
||||
});
|
||||
Route::post("/logout", LogoutController::class);
|
||||
});
|
||||
|
||||
Route::middleware("guest")->group(function(): void {
|
||||
Route::middleware("guest")->group(function (): void {
|
||||
Route::get("login", fn() => inertia("Login"))->name("login");
|
||||
Route::get("login/google/start", [GoogleController::class, "redirect"])
|
||||
->name("login.google.start");
|
||||
Route::get("login/google/end", [GoogleController::class, "callback"])
|
||||
->name("login.google.end");
|
||||
});
|
||||
});
|
||||
|
43
tests/Feature/AuthenticationTest.php
Normal file
43
tests/Feature/AuthenticationTest.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Tests\TestCase;
|
||||
use Toby\Models\User;
|
||||
|
||||
class AuthenticationTest extends TestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
public function testGuestIsRedirectedFromDashboard(): void
|
||||
{
|
||||
$this->get("/")
|
||||
->assertRedirect();
|
||||
}
|
||||
|
||||
public function testUserIsNotRedirectedFromDashboard(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get("/")
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function testUserCanLogout(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->assertAuthenticated();
|
||||
|
||||
$this->post("/logout")
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertGuest();
|
||||
}
|
||||
}
|
@ -4,14 +4,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Tests\TestCase;
|
||||
use Toby\Models\User;
|
||||
|
||||
class InertiaTest extends TestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
public function testInertia(): void
|
||||
{
|
||||
$response = $this->get("/");
|
||||
$user = User::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get("/");
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertInertia(fn(Assert $page) => $page->component("Dashboard"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user