first commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->artisan('db:seed');
|
||||
});
|
||||
|
||||
test('attach and detach permission', function () {
|
||||
$role = Role::factory()->create();
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$role->attachPermission($permission);
|
||||
$this->assertTrue($role->fresh()->hasPermission($permission->name));
|
||||
|
||||
$role->detachPermission($permission);
|
||||
$this->assertFalse($role->fresh()->hasPermission($permission->name));
|
||||
});
|
||||
|
||||
test('attach permissions supports id and object array', function () {
|
||||
$role = Role::factory()->create();
|
||||
$p1 = Permission::factory()->create();
|
||||
$p2 = Permission::factory()->create();
|
||||
|
||||
$role->attachPermissions([$p1, ['id' => $p2->id]]);
|
||||
|
||||
$this->assertTrue($role->fresh()->hasPermission($p1->name));
|
||||
$this->assertTrue($role->fresh()->hasPermission($p2->name));
|
||||
});
|
||||
|
||||
test('sync permissions replaces permissions', function () {
|
||||
$role = Role::factory()->create();
|
||||
$p1 = Permission::factory()->create();
|
||||
$p2 = Permission::factory()->create();
|
||||
|
||||
$role->attachPermission($p1);
|
||||
$role->syncPermissions([$p2->id]);
|
||||
|
||||
$fresh = $role->fresh();
|
||||
$this->assertFalse($fresh->hasPermission($p1->name));
|
||||
$this->assertTrue($fresh->hasPermission($p2->name));
|
||||
});
|
||||
|
||||
test('save permissions with empty array detaches all', function () {
|
||||
$role = Role::factory()->create();
|
||||
$p1 = Permission::factory()->create();
|
||||
|
||||
$role->attachPermission($p1);
|
||||
$role->savePermissions([]);
|
||||
|
||||
$this->assertCount(0, $role->fresh()->permissions);
|
||||
});
|
||||
|
||||
test('cached permissions are returned', function () {
|
||||
$role = Role::factory()->create();
|
||||
$p1 = Permission::factory()->create();
|
||||
$role->attachPermission($p1);
|
||||
|
||||
$cached = $role->cachedPermissions();
|
||||
|
||||
$this->assertTrue($cached->contains('name', $p1->name));
|
||||
});
|
||||
|
||||
test('save clears cache', function () {
|
||||
$role = Role::factory()->create();
|
||||
$p1 = Permission::factory()->create();
|
||||
$role->attachPermission($p1);
|
||||
|
||||
$role->cachedPermissions();
|
||||
$role->detachPermission($p1);
|
||||
$role->save();
|
||||
|
||||
$this->assertFalse($role->cachedPermissions()->contains('name', $p1->name));
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->artisan('db:seed');
|
||||
});
|
||||
|
||||
test('has role returns true when matching role', function () {
|
||||
$role = Role::factory()->create(['name' => 'Editor']);
|
||||
$user = User::factory()->create(['role_id' => $role->id]);
|
||||
|
||||
$this->assertTrue($user->hasRole('Editor'));
|
||||
$this->assertFalse($user->hasRole('Admin'));
|
||||
});
|
||||
|
||||
test('has permission returns true when role has permission', function () {
|
||||
$role = Role::factory()->create();
|
||||
$permission = Permission::factory()->create(['name' => 'something.do']);
|
||||
$role->attachPermission($permission);
|
||||
|
||||
$user = User::factory()->create(['role_id' => $role->id]);
|
||||
|
||||
$this->assertTrue($user->hasPermission('something.do'));
|
||||
$this->assertFalse($user->hasPermission('something.else'));
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Support\Authorization\PasswordChangeManager;
|
||||
use Illuminate\Cache\CacheManager;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\UpdatesSettings;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
uses(UpdatesSettings::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->artisan('db:seed');
|
||||
|
||||
$this->manager = new PasswordChangeManager(app(CacheManager::class));
|
||||
});
|
||||
|
||||
test('force password change returns false when feature disabled', function () {
|
||||
$this->setSettings(['password-change.enabled' => false]);
|
||||
|
||||
$user = User::factory()->create(['force_password_change' => true]);
|
||||
|
||||
$this->assertFalse($this->manager->forcePasswordChange($user));
|
||||
$this->assertFalse($this->manager->isPasswordChangeForcedForUser($user));
|
||||
});
|
||||
|
||||
test('force password change returns false when user flag false', function () {
|
||||
$this->setSettings(['password-change.enabled' => true]);
|
||||
|
||||
$user = User::factory()->create(['force_password_change' => false]);
|
||||
|
||||
$this->assertFalse($this->manager->forcePasswordChange($user));
|
||||
});
|
||||
|
||||
test('force password change sets cache when enabled and flagged', function () {
|
||||
$this->setSettings(['password-change.enabled' => true]);
|
||||
|
||||
$user = User::factory()->create(['force_password_change' => true]);
|
||||
|
||||
$this->assertTrue($this->manager->forcePasswordChange($user));
|
||||
$this->assertTrue($this->manager->isPasswordChangeForcedForUser($user));
|
||||
});
|
||||
|
||||
test('lift password change request clears cache', function () {
|
||||
$this->setSettings(['password-change.enabled' => true]);
|
||||
|
||||
$user = User::factory()->create(['force_password_change' => true]);
|
||||
|
||||
$this->manager->forcePasswordChange($user);
|
||||
$this->manager->liftPasswordChangeRequest($user);
|
||||
|
||||
$this->assertFalse($this->manager->isPasswordChangeForcedForUser($user));
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Support\Demo;
|
||||
|
||||
beforeEach(function () {
|
||||
config([
|
||||
'demo.enabled' => true,
|
||||
'demo.protected_users' => ['admin'],
|
||||
'demo.message' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
test('nobody is protected while demo mode is off', function () {
|
||||
config(['demo.enabled' => false]);
|
||||
|
||||
$this->assertFalse(Demo::enabled());
|
||||
$this->assertFalse(Demo::isProtectedUser(new User(['username' => 'admin'])));
|
||||
});
|
||||
|
||||
test('a guest is never protected', function () {
|
||||
$this->assertFalse(Demo::isProtectedUser(null));
|
||||
});
|
||||
|
||||
test('a protected account is matched on its username', function () {
|
||||
$this->assertTrue(Demo::isProtectedUser(new User(['username' => 'admin'])));
|
||||
});
|
||||
|
||||
test('a protected account is matched on its email', function () {
|
||||
config(['demo.protected_users' => ['admin@example.com']]);
|
||||
|
||||
$this->assertTrue(Demo::isProtectedUser(new User(['email' => 'admin@example.com'])));
|
||||
});
|
||||
|
||||
test('matching ignores case on both sides', function () {
|
||||
config(['demo.protected_users' => ['ADMIN']]);
|
||||
|
||||
$this->assertTrue(Demo::isProtectedUser(new User(['username' => 'Admin'])));
|
||||
});
|
||||
|
||||
test('an ordinary account is not protected', function () {
|
||||
$this->assertFalse(Demo::isProtectedUser(new User([
|
||||
'username' => 'jane',
|
||||
'email' => 'jane@example.com',
|
||||
])));
|
||||
});
|
||||
|
||||
test('a user without a username is not protected by an empty match', function () {
|
||||
config(['demo.protected_users' => ['']]);
|
||||
|
||||
$this->assertFalse(Demo::isProtectedUser(new User(['email' => 'jane@example.com'])));
|
||||
});
|
||||
|
||||
test('the configured message overrides every reason', function () {
|
||||
config(['demo.message' => 'Nope.']);
|
||||
|
||||
$this->assertSame('Nope.', Demo::message());
|
||||
$this->assertSame('Nope.', Demo::message('Something more specific.'));
|
||||
});
|
||||
|
||||
test('a reason falls back to the generic refusal', function () {
|
||||
$this->assertSame('This action is disabled in the demo.', Demo::message());
|
||||
$this->assertSame('Something more specific.', Demo::message('Something more specific.'));
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use App\Support\Enum\UserStatus;
|
||||
use Tests\UpdatesSettings;
|
||||
|
||||
uses(UpdatesSettings::class);
|
||||
|
||||
test('lists returns active banned unconfirmed when approval disabled', function () {
|
||||
$this->setSettings(['approval.enabled' => false]);
|
||||
|
||||
$statuses = UserStatus::lists();
|
||||
|
||||
$this->assertArrayHasKey(UserStatus::ACTIVE->value, $statuses);
|
||||
$this->assertArrayHasKey(UserStatus::BANNED->value, $statuses);
|
||||
$this->assertArrayHasKey(UserStatus::UNCONFIRMED->value, $statuses);
|
||||
$this->assertArrayNotHasKey(UserStatus::WAITING_APPROVAL->value, $statuses);
|
||||
});
|
||||
|
||||
test('lists includes waiting approval when approval enabled', function () {
|
||||
$this->setSettings(['approval.enabled' => true]);
|
||||
|
||||
$statuses = UserStatus::lists();
|
||||
|
||||
$this->assertArrayHasKey(UserStatus::WAITING_APPROVAL->value, $statuses);
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use App\Support\Locale;
|
||||
|
||||
test('flag url returns url for known locale', function () {
|
||||
$this->assertStringContainsString('/flags/GB.png', Locale::flagUrl('en'));
|
||||
$this->assertStringContainsString('/flags/DE.png', Locale::flagUrl('de'));
|
||||
$this->assertStringContainsString('/flags/RS.png', Locale::flagUrl('sr'));
|
||||
});
|
||||
|
||||
test('flag url returns null for unknown locale', function () {
|
||||
$this->assertNull(Locale::flagUrl('fr'));
|
||||
});
|
||||
|
||||
test('validate locale accepts available locales', function () {
|
||||
foreach (Locale::AVAILABLE_LOCALES as $locale) {
|
||||
$this->assertTrue(Locale::validateLocale($locale));
|
||||
}
|
||||
});
|
||||
|
||||
test('validate locale rejects unknown locale', function () {
|
||||
$this->assertFalse(Locale::validateLocale('fr'));
|
||||
$this->assertFalse(Locale::validateLocale(''));
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Support\Sidebar\Item;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->artisan('db:seed');
|
||||
});
|
||||
|
||||
test('create builds item with title', function () {
|
||||
$item = Item::create('Users');
|
||||
|
||||
$this->assertSame('Users', $item->getTitle());
|
||||
});
|
||||
|
||||
test('href takes priority over route', function () {
|
||||
$item = Item::create('Foo')
|
||||
->href('https://example.com/bar');
|
||||
|
||||
$this->assertSame('https://example.com/bar', $item->getHref());
|
||||
});
|
||||
|
||||
test('get href resolves named route', function () {
|
||||
$item = Item::create('Foo')->route('dashboard');
|
||||
|
||||
$this->assertSame(route('dashboard'), $item->getHref());
|
||||
});
|
||||
|
||||
test('get href returns null when neither set', function () {
|
||||
$this->assertNull(Item::create('Foo')->getHref());
|
||||
});
|
||||
|
||||
test('icon setter and getter', function () {
|
||||
$item = Item::create('Foo')->icon('bi-people');
|
||||
|
||||
$this->assertSame('bi-people', $item->getIcon());
|
||||
});
|
||||
|
||||
test('active path setter and getter', function () {
|
||||
$item = Item::create('Foo')->active('users*');
|
||||
|
||||
$this->assertSame('users*', $item->getActivePath());
|
||||
});
|
||||
|
||||
test('dropdown returns false without children', function () {
|
||||
$this->assertFalse(Item::create('Foo')->isDropdown());
|
||||
});
|
||||
|
||||
test('add children makes item a dropdown', function () {
|
||||
$item = Item::create('Foo')->addChildren([
|
||||
Item::create('Child 1'),
|
||||
Item::create('Child 2'),
|
||||
]);
|
||||
|
||||
$this->assertTrue($item->isDropdown());
|
||||
$this->assertCount(2, $item->children());
|
||||
});
|
||||
|
||||
test('expanded path collects children active paths', function () {
|
||||
$item = Item::create('Foo')->addChildren([
|
||||
Item::create('Child 1')->active('users*'),
|
||||
Item::create('Child 2')->active('roles*'),
|
||||
]);
|
||||
|
||||
$this->assertSame(['users*', 'roles*'], $item->getExpandedPath());
|
||||
});
|
||||
|
||||
test('authorize returns true when no permissions set', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->assertTrue(Item::create('Foo')->authorize($user));
|
||||
});
|
||||
|
||||
test('authorize calls closure when closure provided', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$item = Item::create('Foo')->permissions(fn ($u) => $u->id === $user->id);
|
||||
|
||||
$this->assertTrue($item->authorize($user));
|
||||
});
|
||||
|
||||
test('authorize checks user has permission', function () {
|
||||
$user = Mockery::mock(User::class)->makePartial();
|
||||
$user->shouldReceive('hasPermission')->with('users.manage')->andReturn(true);
|
||||
$user->shouldReceive('hasPermission')->with('roles.manage')->andReturn(false);
|
||||
|
||||
$allowed = Item::create('A')->permissions(['users.manage']);
|
||||
$denied = Item::create('B')->permissions(['users.manage', 'roles.manage']);
|
||||
|
||||
$this->assertTrue($allowed->authorize($user));
|
||||
$this->assertFalse($denied->authorize($user));
|
||||
});
|
||||
Reference in New Issue
Block a user