$allowedByTypeById = ['fallback' => [], 'user' => [], 'role' => []];
/** @var EntityPermission $permission */
foreach ($relevantPermissions as $permission) {
- $allowedByTypeById[$permission->getAssignedType()][$permission->getAssignedTypeId()] = $permission->$permission;
+ $allowedByTypeById[$permission->getAssignedType()][$permission->getAssignedTypeId()] = boolval($permission->$action);
}
$inheriting = !isset($allowedByTypeById['fallback'][0]);
--- /dev/null
+# Permission Scenario Testing
+
+Due to complexity that can arise in the various combinations of permissions, this document details scenarios and their expected results.
+
+Test cases are written ability abstract, since all abilities should act the same in theory. Functional test cases may test abilities separate due to implementation differences.
+
+## Cases
+
+### Entity Role Permissions
+
+These are tests related to entity-level role-specific permission overrides.
+
+#### entity_role_01 - Explicit allow
+
+- Page permissions have inherit disabled.
+- Role A has explicit page permission.
+- User has Role A.
+
+User should have page permission.
+
+#### entity_role_02 - Explicit deny
+
+- Page permissions have inherit disabled.
+- Role A has explicit page permission.
+- User has Role A.
+
+User should not have permission.
+
+#### entity_role_03 - Same level conflicting
+
+- Page permissions have inherit disabled.
+- Role A has explicit page permission.
+- Role B has explicit blocked page permission.
+- User has both Role A & B.
+
+User should have page permission. Explicit grant overrides explicit deny at same level.
+
--- /dev/null
+<?php
+
+namespace Tests\Permissions\Scenarios;
+
+use BookStack\Entities\Models\Page;
+use Tests\TestCase;
+
+// Cases defined in dev/docs/permission-scenario-testing.md
+
+class EntityRolePermissions extends TestCase
+{
+ public function test_01_explicit_allow()
+ {
+ $user = $this->getViewer();
+ $role = $user->roles->first();
+ $page = $this->entities->page();
+ $this->entities->setPermissions($page, ['view'], [$role], false);
+
+ $this->actingAs($user);
+ $this->assertTrue(userCan('page-view', $page));
+ $this->assertNotNull(Page::visible()->findOrFail($page->id));
+ }
+
+ public function test_02_explicit_deny()
+ {
+ $user = $this->getViewer();
+ $role = $user->roles->first();
+ $page = $this->entities->page();
+ $this->entities->setPermissions($page, ['edit'], [$role], false);
+
+ $this->actingAs($user);
+ $this->assertFalse(userCan('page-view', $page));
+ $this->assertNull(Page::visible()->find($page->id));
+ }
+
+ public function test_03_same_level_conflicting()
+ {
+ $user = $this->getViewer();
+ $roleA = $user->roles->first();
+ $roleB = $this->createNewRole();
+ $user->attachRole($roleB);
+
+ $page = $this->entities->page();
+ // TODO - Can't do this as second call will overwrite first
+ $this->entities->setPermissions($page, ['edit'], [$roleA], false);
+ $this->entities->setPermissions($page, ['view'], [$roleB], false);
+
+ $this->actingAs($user);
+ $this->assertFalse(userCan('page-view', $page));
+ $this->assertNull(Page::visible()->find($page->id));
+ }
+}