Login and tests WIP

This commit is contained in:
Ryan Scherler
2020-10-21 23:07:36 -07:00
parent c1e680144a
commit b237f433bf
13 changed files with 80 additions and 87 deletions
+2 -2
View File
@@ -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;
}
+3 -3
View File
@@ -15,12 +15,12 @@ return [
'signin' => 'Sign in to your account',
'username' => [
'labels' => [
'email' => 'E-mail Address',
'username' => 'Username',
'password' => 'Password',
],
];
+23 -6
View File
@@ -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 -1
View File
@@ -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 -13
View File
@@ -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()
-44
View File
@@ -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());
}
}
+2 -2
View File
@@ -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
View File
@@ -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'),
},
},
}),
+23 -5
View File
@@ -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;
}
}