Are you mean this https://filamentphp.com/plugins/bezhansalleh-shield
that package is overkill for me
may be just add a role column into users table ?
// migration
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->unsignedTinyInteger('role')->default(User::MEMBER_ROLE_ID);
// model
class User extends Authenticatable implements FilamentUser
{
use HasFactory, Notifiable;
const SUPER_ADMIN_ROLE_ID = 1;
const MEMBER_ROLE_ID = 4;
protected $fillable = [
'name',
'email',
'role',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $attributes = [
'role' => self::MEMBER_ROLE_ID,
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
public function isSuperAdmin(): bool
{
return $this->role === self::SUPER_ADMIN_ROLE_ID;
}
public function canAccessPanel(Panel $panel): bool
{
return $this->isSuperAdmin();
}
}
add a new config file
<?php
return [
/*
|--------------------------------------------------------------------------
| Site Config
|--------------------------------------------------------------------------
*/
'user_roles' => [
1 => 'super admin',
2 => 'admin',
3 => 'vip',
4 => 'member',
],
];
add a seeder for dev
class UserSeeder extends Seeder
{
public function run(): void
{
$users = [
'admin',
'test1',
'test2',
'test3',
];
$roleKeys = array_keys(config('cfg.user_roles'));
throw_if(
count($users) != count($roleKeys),
'The count of users and roles not matched.'
);
$users = array_combine($roleKeys, $users);
foreach($users as $role => $userName) {
User::factory()->create([
'name' => $userName,
'email' => "{$userName}@example.com",
'role' => $role,
]);
}
}
}
and then add two state in to User factory
class UserFactory extends Factory
{
/**
* The current password being used by the factory.
*/
protected static ?string $password;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
...
}
/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): static
{
...
}
/**
* Indicate that the user factory use super admin role.
*/
public function superAdminRole(): Factory
{
return $this->state(fn (array $attributes) => [
'role' => User::SUPER_ADMIN_ROLE_ID,
]);
}
/**
* Indicate that the user factory use random role.
*/
public function randomRole(): Factory
{
return $this->state(fn (array $attributes) => [
'role' => fake()->randomKey(config('cfg.user_roles')),
]);
}
}
so you can call this to create user
User::factory()->superAdminRole()->create();
User::factory()->count(10)->superAdminRole()->create();
User::factory()->randomRole()->create();
User::factory()->count(10)->randomRole()->create();
finally write a test
Edited:
<?php
use App\Models\User;
use Filament\Pages\Auth\Login;
use Livewire\Livewire;
use function Pest\Laravel\{actingAs, get};
test('admin panel login screen can be rendered', function () {
get('/admin')
->assertRedirect('/admin/login');
get('/admin/login')
->assertOk()
->assertSeeLivewire(Login::class);
});
test('only super admin can authenticate using the admin panel login screen', function () {
$component = Livewire::test(Login::class);
$roles = array_keys(config('cfg.user_roles'));
foreach ($roles as $role) {
$user = User::factory()->create(['role' => $role]);
$component
->fillForm([
'email' => $user->email,
'password' => 'password',
])
->call('authenticate');
if ($user->role === 1) {
$component
->assertHasNoFormErrors()
->assertRedirect('/admin');
$this->assertAuthenticated();
continue;
}
$component
->assertHasFormErrors()
->assertNoRedirect();
$this->assertGuest();
}
});
test('super admin can not authenticate with invalid password', function () {
$superAdmin = User::factory()->superAdminRole()->create();
Livewire::test(Login::class)
->fillForm([
'email' => $superAdmin->email,
'password' => 'wrong-password',
])
->call('authenticate')
->assertHasFormErrors()
->assertNoRedirect();
$this->assertGuest();
});
test('super admin can logout', function () {
$superAdmin = User::factory()->superAdminRole()->create();
actingAs($superAdmin)
->post('/admin/logout')
->assertRedirect('/admin/login');
$this->assertGuest();
});