mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Login and tests WIP
This commit is contained in:
Vendored
+2
-2
@@ -699,7 +699,7 @@ video {
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
border-color: #E0E3E6;
|
||||
border-color: #A4ACB7;
|
||||
border-width: 1px;
|
||||
border-radius: 0.25rem;
|
||||
padding-top: 0.5rem;
|
||||
@@ -876,7 +876,7 @@ video {
|
||||
width: 1em;
|
||||
color: #4299e1;
|
||||
background-color: #fff;
|
||||
border-color: #E0E3E6;
|
||||
border-color: #A4ACB7;
|
||||
border-width: 1px;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ return [
|
||||
|
||||
'signin' => 'Sign in to your account',
|
||||
|
||||
'username' => [
|
||||
'labels' => [
|
||||
|
||||
'email' => 'E-mail Address',
|
||||
|
||||
'username' => 'Username',
|
||||
|
||||
'password' => 'Password',
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
@props([
|
||||
'name',
|
||||
'hint' => false,
|
||||
'help' => false,
|
||||
'hasError' => $errors->has($name) ? ' text-red-600' : '',
|
||||
])
|
||||
|
||||
<x-filament::label>
|
||||
<span class="inline-flex items-center space-x-2">
|
||||
<input type="checkbox" name="{{ $name }}" {{ $attributes->merge(['class' => 'form-checkbox'.$hasError]) }}{{ old($name) ? ' checked' : '' }}>
|
||||
<span class="ml-2">{{ $slot }}</span>
|
||||
</span>
|
||||
</x-filament::label>
|
||||
<div class="space-y-1">
|
||||
<x-filament::label>
|
||||
<span class="inline-flex items-center space-x-2">
|
||||
<input type="checkbox" name="{{ $name }}" {{ $attributes->merge(['class' => 'form-checkbox'.$hasError]) }}{{ old($name) ? ' checked' : '' }}>
|
||||
<span class="inline-flex items-baseline space-x-4">
|
||||
<span>{{ $slot }}</span>
|
||||
@if ($help)
|
||||
<x-filament::hint>
|
||||
{{ $hint }}
|
||||
</x-filament::hint>
|
||||
@endif
|
||||
</span>
|
||||
</span>
|
||||
</x-filament::label>
|
||||
<x-filament::error :name="$name" />
|
||||
@if ($help)
|
||||
<x-filament::help class="inline-block">
|
||||
{{ $help }}
|
||||
</x-filament::help>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<span {{ $attributes->merge(['class' => 'text-sm font-normal leading-tight text-gray-700']) }}>
|
||||
{{ $slot }}
|
||||
</span>
|
||||
@@ -0,0 +1,3 @@
|
||||
<span {{ $attributes->merge(['class' => 'font-normal font-mono text-xs leading-tight text-gray-700']) }}>
|
||||
{{ $slot }}
|
||||
</span>
|
||||
@@ -8,7 +8,7 @@
|
||||
])
|
||||
|
||||
<div {{ $attributes->merge(['class' => $errorClasses]) }}>
|
||||
<div class="flex items-center justify-between mb-1 space-x-2">
|
||||
<div class="flex items-center justify-between mb-2 space-x-2">
|
||||
<x-filament::label :for="$name">
|
||||
{{ $label ?? $name }}
|
||||
@if ($required)
|
||||
@@ -16,12 +16,16 @@
|
||||
@endif
|
||||
</x-filament::label>
|
||||
@if ($hint)
|
||||
<div class="font-mono text-xs leading-tight text-gray-600">{{ $hint }}</div>
|
||||
<x-filament::hint>
|
||||
{{ $hint }}
|
||||
</x-filament::hint>
|
||||
@endif
|
||||
</div>
|
||||
{{ $slot }}
|
||||
<x-filament::error :name="$name" class="mt-1" />
|
||||
@if ($help)
|
||||
<div class="text-sm leading-tight text-gray-600 mt-1">{{ $help }}</div>
|
||||
<x-filament::help class="mt-1">
|
||||
{{ $help }}
|
||||
</x-filament::help>
|
||||
@endif
|
||||
</div>
|
||||
@@ -1,3 +1,3 @@
|
||||
<label {{ $attributes->merge(['class' => 'text-gray-700 text-sm font-semibold cursor-pointer']) }}>
|
||||
<label {{ $attributes->merge(['class' => 'text-sm leading-tight font-semibold cursor-pointer']) }}>
|
||||
{{ $slot }}
|
||||
</label>
|
||||
@@ -1,9 +1,9 @@
|
||||
<form wire:submit.prevent="login" class="flex flex-col space-y-4">
|
||||
<x-filament::input-group-stacked :name="$this->username()" :label="$this->label()" required>
|
||||
<x-filament::input :type="$this->type()" :name="$this->username()" :wire:model.defer="$this->username()" :id="$this->username()" required :autocomplete="$this->username()" />
|
||||
<form wire:submit.prevent="login" class="space-y-4">
|
||||
<x-filament::input-group-stacked name="email" :label="__('filament::auth.labels.email')" required>
|
||||
<x-filament::input type="email" name="email" wire:model.defer="email" id="email" required autocomplete="email" />
|
||||
</x-filament::input-group-stacked>
|
||||
|
||||
<x-filament::input-group-stacked name="password" :label="__('Password')" required>
|
||||
<x-filament::input-group-stacked name="password" :label="__('filament::auth.labels.password')" required>
|
||||
@if (Route::has('filament.password.forgot'))
|
||||
<x-slot name="hint">
|
||||
<a href="{{ route('filament.password.forgot') }}" class="text-current hover:text-blue">
|
||||
@@ -11,10 +11,10 @@
|
||||
</a>
|
||||
</x-slot>
|
||||
@endif
|
||||
<x-filament::input type="password" name="password" wire:model.defer="password" id="password" :placeholder="__('Password')" required autocomplete="current-password" />
|
||||
<x-filament::input type="password" name="password" wire:model.defer="password" id="password" required autocomplete="current-password" />
|
||||
</x-filament::input-group-stacked>
|
||||
|
||||
<x-filament::checkbox name="remember">
|
||||
<x-filament::checkbox name="remember" wire:model.defer="remember">
|
||||
{{ __('Remember Me') }}
|
||||
</x-filament::checkbox>
|
||||
|
||||
|
||||
@@ -5,29 +5,24 @@ namespace Filament\Http\Livewire\Auth;
|
||||
use Livewire\Component;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Filament\Traits\AuthenticatesUsers;
|
||||
use Filament\Traits\ThrottlesLogins;
|
||||
|
||||
class Login extends Component
|
||||
{
|
||||
use AuthenticatesUsers, ThrottlesLogins;
|
||||
use ThrottlesLogins;
|
||||
|
||||
public $email;
|
||||
public $password;
|
||||
public $remember = false;
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
{
|
||||
$data = $this->validate([
|
||||
$this->username() => 'required|email',
|
||||
'email' => 'required|email',
|
||||
'password' => 'required|min:8',
|
||||
]);
|
||||
|
||||
// If the class is using the ThrottlesLogins trait, we can automatically throttle
|
||||
// the login attempts for this application. We'll key this by the username and
|
||||
// the IP address of the client making these requests into this application.
|
||||
if (method_exists($this, 'hasTooManyLoginAttempts') &&
|
||||
$this->hasTooManyLoginAttempts($request)) {
|
||||
if ($this->hasTooManyLoginAttempts($request)) {
|
||||
$this->fireLockoutEvent($request);
|
||||
|
||||
return $this->sendLockoutResponse($request);
|
||||
@@ -37,12 +32,9 @@ class Login extends Component
|
||||
return redirect()->intended(route('filament.dashboard'));
|
||||
}
|
||||
|
||||
// If the login attempt was unsuccessful we will increment the number of attempts
|
||||
// to login and redirect the user back to the login form. Of course, when this
|
||||
// user surpasses their maximum number of attempts they will get locked out.
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
||||
$this->addError($this->username(), trans('auth.failed'));
|
||||
$this->addError('email', trans('auth.failed'));
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Traits;
|
||||
|
||||
use Illuminate\Auth\Events\Lockout;
|
||||
use Illuminate\Cache\RateLimiter;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
trait AuthenticatesUsers
|
||||
{
|
||||
/**
|
||||
* Get the login username to be used.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function username()
|
||||
{
|
||||
return 'email';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the translated input type based on the username.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return ($this->username() === 'email') ? 'email' : 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the translated label based on the username.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function label()
|
||||
{
|
||||
return trans('filament::auth.username.'.$this->username());
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ trait ThrottlesLogins
|
||||
);
|
||||
|
||||
throw ValidationException::withMessages([
|
||||
$this->username() => [Lang::get('auth.throttle', [
|
||||
'email' => [Lang::get('auth.throttle', [
|
||||
'seconds' => $seconds,
|
||||
'minutes' => ceil($seconds / 60),
|
||||
])],
|
||||
@@ -90,7 +90,7 @@ trait ThrottlesLogins
|
||||
*/
|
||||
protected function throttleKey(Request $request)
|
||||
{
|
||||
return Str::lower($request->input($this->username())).'|'.$request->ip();
|
||||
return Str::lower($request->input('email')).'|'.$request->ip();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -58,11 +58,11 @@ module.exports = {
|
||||
customForms: (theme) => ({
|
||||
default: {
|
||||
input: {
|
||||
borderColor: theme('colors.gray.400'),
|
||||
borderColor: theme('colors.gray.600'),
|
||||
boxShadow: theme('boxShadow.sm'),
|
||||
},
|
||||
checkbox: {
|
||||
borderColor: theme('colors.gray.400'),
|
||||
borderColor: theme('colors.gray.600'),
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -63,12 +63,30 @@ class LoginTest extends TestCase
|
||||
->assertHasErrors(['password' => 'min']);
|
||||
}
|
||||
|
||||
public function test_bad_credentials_show_error_on_login()
|
||||
public function test_bad_credentials_show_error()
|
||||
{
|
||||
$this->invalid_login()
|
||||
->assertHasErrors('email');
|
||||
}
|
||||
|
||||
public function test_bad_credentials_show_error_due_to_login_throttling()
|
||||
{
|
||||
foreach (range(0, 3) as $attempt) { // attempt 4 invalid logins
|
||||
$this->invalid_login();
|
||||
}
|
||||
|
||||
// 5th invalid login attempt should return validation error
|
||||
$this->invalid_login()
|
||||
->assertHasErrors('email');
|
||||
}
|
||||
|
||||
private function invalid_login()
|
||||
{
|
||||
$component = Livewire::test(Login::class)
|
||||
->set('email', 'example@example.com')
|
||||
->set('password', 'wrongpassword')
|
||||
->call('login')
|
||||
->assertHasErrors('password');
|
||||
->set('email', 'example@example.com')
|
||||
->set('password', 'wrongpassword')
|
||||
->call('login');
|
||||
|
||||
return $component;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user