From fa383964796451265ba6225f4eb078cdd4d83f48 Mon Sep 17 00:00:00 2001 From: jeremy bayse Date: Wed, 24 Jun 2026 06:53:19 +0200 Subject: [PATCH] feat: add user authentication with livewire components --- app/Livewire/Auth/Login.php | 57 +++++++++++++ app/Livewire/Auth/Register.php | 42 ++++++++++ resources/views/chatbot-admin.blade.php | 15 +++- resources/views/layouts/auth.blade.php | 49 +++++++++++ resources/views/livewire/auth/login.blade.php | 68 +++++++++++++++ .../views/livewire/auth/register.blade.php | 82 +++++++++++++++++++ resources/views/welcome.blade.php | 15 +++- routes/web.php | 34 ++++++-- tests/Feature/ExampleTest.php | 17 +++- 9 files changed, 368 insertions(+), 11 deletions(-) create mode 100644 app/Livewire/Auth/Login.php create mode 100644 app/Livewire/Auth/Register.php create mode 100644 resources/views/layouts/auth.blade.php create mode 100644 resources/views/livewire/auth/login.blade.php create mode 100644 resources/views/livewire/auth/register.blade.php diff --git a/app/Livewire/Auth/Login.php b/app/Livewire/Auth/Login.php new file mode 100644 index 0000000..8fe3818 --- /dev/null +++ b/app/Livewire/Auth/Login.php @@ -0,0 +1,57 @@ + 'required|string|email', + 'password' => 'required|string', + ]; + + public function login() + { + $this->validate(); + + $throttleKey = Str::transliterate(Str::lower($this->email).'|'.request()->ip()); + + if (RateLimiter::tooManyAttempts($throttleKey, 5)) { + $seconds = RateLimiter::availableIn($throttleKey); + throw ValidationException::withMessages([ + 'email' => trans('auth.throttle', [ + 'seconds' => $seconds, + 'minutes' => ceil($seconds / 60), + ]), + ]); + } + + if (!Auth::attempt(['email' => $this->email, 'password' => $this->password], $this->remember)) { + RateLimiter::hit($throttleKey, 60); + + throw ValidationException::withMessages([ + 'email' => __('auth.failed'), + ]); + } + + RateLimiter::clear($throttleKey); + session()->regenerate(); + + return redirect()->intended('/'); + } + + public function render() + { + return view('livewire.auth.login') + ->layout('layouts.auth', ['title' => 'Connexion']); + } +} diff --git a/app/Livewire/Auth/Register.php b/app/Livewire/Auth/Register.php new file mode 100644 index 0000000..4559345 --- /dev/null +++ b/app/Livewire/Auth/Register.php @@ -0,0 +1,42 @@ +validate([ + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], + 'password' => ['required', 'string', 'confirmed', Rules\Password::defaults()], + ]); + + $user = User::create([ + 'name' => $this->name, + 'email' => $this->email, + 'password' => Hash::make($this->password), + ]); + + Auth::login($user); + + return redirect('/'); + } + + public function render() + { + return view('livewire.auth.register') + ->layout('layouts.auth', ['title' => 'Inscription']); + } +} diff --git a/resources/views/chatbot-admin.blade.php b/resources/views/chatbot-admin.blade.php index e160192..8aabc58 100644 --- a/resources/views/chatbot-admin.blade.php +++ b/resources/views/chatbot-admin.blade.php @@ -79,11 +79,24 @@

-
+
Actif + + @auth +
+
+

Connecté en tant que

+

{{ auth()->user()->name }}

+
+
+ + Déconnexion + +
+ @endauth
diff --git a/resources/views/layouts/auth.blade.php b/resources/views/layouts/auth.blade.php new file mode 100644 index 0000000..84811ab --- /dev/null +++ b/resources/views/layouts/auth.blade.php @@ -0,0 +1,49 @@ + + + + + + {{ $title ?? 'Connexion' }} - Chatbot AGGLO + + + + + + + + + + + @livewireStyles + + + + + + +
+
+ +
+ {{ $slot }} +
+ + @livewireScripts + + diff --git a/resources/views/livewire/auth/login.blade.php b/resources/views/livewire/auth/login.blade.php new file mode 100644 index 0000000..5242601 --- /dev/null +++ b/resources/views/livewire/auth/login.blade.php @@ -0,0 +1,68 @@ +
+
+ + Console Chatbot AGGLO + +

Connexion

+

Accédez à votre tableau de bord d'administration

+
+ +
+
+ +
+ +
+ +
+ @error('email') + {{ $message }} + @enderror +
+ + +
+
+ +
+
+ +
+ @error('password') + {{ $message }} + @enderror +
+ + +
+ + +
+ + +
+ +
+
+ +
+ Pas encore de compte ? + Créer un compte +
+
+
diff --git a/resources/views/livewire/auth/register.blade.php b/resources/views/livewire/auth/register.blade.php new file mode 100644 index 0000000..7c3a441 --- /dev/null +++ b/resources/views/livewire/auth/register.blade.php @@ -0,0 +1,82 @@ +
+
+ + Console Chatbot AGGLO + +

Inscription

+

Créez votre compte administrateur

+
+ +
+
+ +
+ +
+ +
+ @error('name') + {{ $message }} + @enderror +
+ + +
+ +
+ +
+ @error('email') + {{ $message }} + @enderror +
+ + +
+ +
+ +
+ @error('password') + {{ $message }} + @enderror +
+ + +
+ +
+ +
+
+ + +
+ +
+
+ +
+ Déjà inscrit ? + Se connecter +
+
+
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index 6195b00..23e38b3 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -72,11 +72,24 @@

-
+
RAG Actif + + @auth +
+
+

Connecté en tant que

+

{{ auth()->user()->name }}

+
+
+ + Déconnexion + +
+ @endauth
diff --git a/routes/web.php b/routes/web.php index 1aca5e7..3cb0d99 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,19 +1,39 @@ group(function () { + Route::get('/login', Login::class)->name('login'); + Route::get('/register', Register::class)->name('register'); }); -// Admin dashboard for a specific chatbot -Route::get('/admin/chatbots/{chatbot:slug}', function (Chatbot $chatbot) { - return view('chatbot-admin', compact('chatbot')); +// Logout route +Route::any('/logout', function () { + Auth::logout(); + request()->session()->invalidate(); + request()->session()->regenerateToken(); + return redirect('/login'); +})->name('logout'); + +// Authenticated administration routes +Route::middleware('auth')->group(function () { + // Global console / Chatbot manager + Route::get('/', function () { + return view('welcome'); + }); + + // Admin dashboard for a specific chatbot + Route::get('/admin/chatbots/{chatbot:slug}', function (Chatbot $chatbot) { + return view('chatbot-admin', compact('chatbot')); + }); }); -// Full page demo testing for a specific chatbot +// Full page demo testing for a specific chatbot (Public/Private as per requirement) Route::get('/chatbot/{chatbot:slug}', function (Chatbot $chatbot) { return view('chatbot-demo', compact('chatbot')); }); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 8364a84..a0c2060 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -2,18 +2,31 @@ namespace Tests\Feature; -// use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Foundation\Testing\RefreshDatabase; +use App\Models\User; use Tests\TestCase; class ExampleTest extends TestCase { + use RefreshDatabase; + /** * A basic test example. */ - public function test_the_application_returns_a_successful_response(): void + public function test_the_application_redirects_unauthenticated_users(): void { $response = $this->get('/'); + $response->assertStatus(302); + $response->assertRedirect('/login'); + } + + public function test_authenticated_users_can_access_the_dashboard(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->get('/'); + $response->assertStatus(200); } }