From a81a56706e8be77586631f3619ad84df36c8d84e Mon Sep 17 00:00:00 2001 From: Dan Brown <ssddanbrown@googlemail.com> Date: Sun, 24 Apr 2016 16:54:20 +0100 Subject: [PATCH] Rolled out new permissions system throughout application --- app/Entity.php | 15 +- app/Http/Controllers/BookController.php | 14 +- app/Http/Controllers/ChapterController.php | 9 +- app/Http/Controllers/PermissionController.php | 1 + app/Permission.php | 6 +- app/Repos/BookRepo.php | 47 +++- app/Repos/ChapterRepo.php | 15 +- app/Repos/EntityRepo.php | 1 + app/Repos/PageRepo.php | 2 + app/Repos/PermissionsRepo.php | 13 +- app/Role.php | 9 + app/Services/ActivityService.php | 12 +- app/Services/RestrictionService.php | 213 ++++++++++++++---- app/helpers.php | 14 +- ...9_100730_add_view_permissions_to_roles.php | 1 + tests/Permissions/RestrictionsTest.php | 4 + tests/Permissions/RolesTest.php | 12 +- tests/TestCase.php | 2 + 18 files changed, 295 insertions(+), 95 deletions(-) diff --git a/app/Entity.php b/app/Entity.php index 35badb461..c084a2870 100644 --- a/app/Entity.php +++ b/app/Entity.php @@ -70,7 +70,20 @@ abstract class Entity extends Ownable */ public function hasRestriction($role_id, $action) { - return $this->restrictions->where('role_id', $role_id)->where('action', $action)->count() > 0; + return $this->restrictions()->where('role_id', '=', $role_id) + ->where('action', '=', $action)->count() > 0; + } + + /** + * Check if this entity has live (active) restrictions in place. + * @param $role_id + * @param $action + * @return bool + */ + public function hasActiveRestriction($role_id, $action) + { + return $this->restricted && $this->restrictions() + ->where('role_id', '=', $role_id)->where('action', '=', $action)->count() > 0; } /** diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 498d6bb7f..356c7508f 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -71,11 +71,7 @@ class BookController extends Controller 'name' => 'required|string|max:255', 'description' => 'string|max:1000' ]); - $book = $this->bookRepo->newFromInput($request->all()); - $book->slug = $this->bookRepo->findSuitableSlug($book->name); - $book->created_by = Auth::user()->id; - $book->updated_by = Auth::user()->id; - $book->save(); + $book = $this->bookRepo->createFromInput($request->all()); Activity::add($book, 'book_create', $book->id); return redirect($book->getUrl()); } @@ -122,10 +118,7 @@ class BookController extends Controller 'name' => 'required|string|max:255', 'description' => 'string|max:1000' ]); - $book->fill($request->all()); - $book->slug = $this->bookRepo->findSuitableSlug($book->name, $book->id); - $book->updated_by = Auth::user()->id; - $book->save(); + $book = $this->bookRepo->updateFromInput($book, $request->all()); Activity::add($book, 'book_update', $book->id); return redirect($book->getUrl()); } @@ -210,6 +203,7 @@ class BookController extends Controller // Add activity for books foreach ($sortedBooks as $bookId) { $updatedBook = $this->bookRepo->getById($bookId); + $this->bookRepo->updateBookPermissions($updatedBook); Activity::add($updatedBook, 'book_sort', $updatedBook->id); } @@ -227,7 +221,7 @@ class BookController extends Controller $this->checkOwnablePermission('book-delete', $book); Activity::addMessage('book_delete', 0, $book->name); Activity::removeEntity($book); - $this->bookRepo->destroyBySlug($bookSlug); + $this->bookRepo->destroy($book); return redirect('/books'); } diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index d1c6c1733..d58be9ba0 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -57,12 +57,9 @@ class ChapterController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('chapter-create', $book); - $chapter = $this->chapterRepo->newFromInput($request->all()); - $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id); - $chapter->priority = $this->bookRepo->getNewPriority($book); - $chapter->created_by = auth()->user()->id; - $chapter->updated_by = auth()->user()->id; - $book->chapters()->save($chapter); + $input = $request->all(); + $input['priority'] = $this->bookRepo->getNewPriority($book); + $chapter = $this->chapterRepo->createFromInput($request->all(), $book); Activity::add($chapter, 'chapter_create', $book->id); return redirect($chapter->getUrl()); } diff --git a/app/Http/Controllers/PermissionController.php b/app/Http/Controllers/PermissionController.php index c565bb20a..3f2eb7f99 100644 --- a/app/Http/Controllers/PermissionController.php +++ b/app/Http/Controllers/PermissionController.php @@ -2,6 +2,7 @@ use BookStack\Exceptions\PermissionsException; use BookStack\Repos\PermissionsRepo; +use BookStack\Services\RestrictionService; use Illuminate\Http\Request; use BookStack\Http\Requests; diff --git a/app/Permission.php b/app/Permission.php index a146dcf63..e3f391562 100644 --- a/app/Permission.php +++ b/app/Permission.php @@ -1,6 +1,4 @@ -<?php - -namespace BookStack; +<?php namespace BookStack; use Illuminate\Database\Eloquent\Model; @@ -16,7 +14,7 @@ class Permission extends Model /** * Get the permission object by name. - * @param $roleName + * @param $name * @return mixed */ public static function getByName($name) diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php index 1a56843ae..864b1e240 100644 --- a/app/Repos/BookRepo.php +++ b/app/Repos/BookRepo.php @@ -1,5 +1,6 @@ <?php namespace BookStack\Repos; +use Alpha\B; use BookStack\Exceptions\NotFoundException; use Illuminate\Support\Str; use BookStack\Book; @@ -123,21 +124,43 @@ class BookRepo extends EntityRepo /** * Get a new book instance from request input. - * @param $input + * @param array $input * @return Book */ - public function newFromInput($input) + public function createFromInput($input) { - return $this->book->newInstance($input); + $book = $this->book->newInstance($input); + $book->slug = $this->findSuitableSlug($book->name); + $book->created_by = auth()->user()->id; + $book->updated_by = auth()->user()->id; + $book->save(); + $this->restrictionService->buildEntityPermissionsForEntity($book); + return $book; } /** - * Destroy a book identified by the given slug. - * @param $bookSlug + * Update the given book from user input. + * @param Book $book + * @param $input + * @return Book */ - public function destroyBySlug($bookSlug) + public function updateFromInput(Book $book, $input) + { + $book->fill($input); + $book->slug = $this->findSuitableSlug($book->name, $book->id); + $book->updated_by = auth()->user()->id; + $book->save(); + $this->restrictionService->buildEntityPermissionsForEntity($book); + return $book; + } + + /** + * Destroy the given book. + * @param Book $book + * @throws \Exception + */ + public function destroy(Book $book) { - $book = $this->getBySlug($bookSlug); foreach ($book->pages as $page) { $this->pageRepo->destroy($page); } @@ -146,9 +169,19 @@ class BookRepo extends EntityRepo } $book->views()->delete(); $book->restrictions()->delete(); + $this->restrictionService->deleteEntityPermissionsForEntity($book); $book->delete(); } + /** + * Alias method to update the book permissions in the RestrictionService. + * @param Book $book + */ + public function updateBookPermissions(Book $book) + { + $this->restrictionService->buildEntityPermissionsForEntity($book); + } + /** * Get the next child element priority. * @param Book $book diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php index 530f550b1..84489c075 100644 --- a/app/Repos/ChapterRepo.php +++ b/app/Repos/ChapterRepo.php @@ -2,6 +2,7 @@ use Activity; +use BookStack\Book; use BookStack\Exceptions\NotFoundException; use Illuminate\Support\Str; use BookStack\Chapter; @@ -78,11 +79,18 @@ class ChapterRepo extends EntityRepo /** * Create a new chapter from request input. * @param $input - * @return $this + * @param Book $book + * @return Chapter */ - public function newFromInput($input) + public function createFromInput($input, Book $book) { - return $this->chapter->fill($input); + $chapter = $this->chapter->newInstance($input); + $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id); + $chapter->created_by = auth()->user()->id; + $chapter->updated_by = auth()->user()->id; + $chapter = $book->chapters()->save($chapter); + $this->restrictionService->buildEntityPermissionsForEntity($chapter); + return $chapter; } /** @@ -100,6 +108,7 @@ class ChapterRepo extends EntityRepo Activity::removeEntity($chapter); $chapter->views()->delete(); $chapter->restrictions()->delete(); + $this->restrictionService->deleteEntityPermissionsForEntity($chapter); $chapter->delete(); } diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php index cb3dd6674..6522e4e9c 100644 --- a/app/Repos/EntityRepo.php +++ b/app/Repos/EntityRepo.php @@ -151,6 +151,7 @@ class EntityRepo } } $entity->save(); + $this->restrictionService->buildEntityPermissionsForEntity($entity); } /** diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php index ef470c01d..bfb0e70a7 100644 --- a/app/Repos/PageRepo.php +++ b/app/Repos/PageRepo.php @@ -168,6 +168,7 @@ class PageRepo extends EntityRepo if ($chapter) $page->chapter_id = $chapter->id; $book->pages()->save($page); + $this->restrictionService->buildEntityPermissionsForEntity($page); return $page; } @@ -583,6 +584,7 @@ class PageRepo extends EntityRepo $page->views()->delete(); $page->revisions()->delete(); $page->restrictions()->delete(); + $this->restrictionService->deleteEntityPermissionsForEntity($page); $page->delete(); } diff --git a/app/Repos/PermissionsRepo.php b/app/Repos/PermissionsRepo.php index 3c5efde23..ab265a45f 100644 --- a/app/Repos/PermissionsRepo.php +++ b/app/Repos/PermissionsRepo.php @@ -4,6 +4,7 @@ use BookStack\Exceptions\PermissionsException; use BookStack\Permission; use BookStack\Role; +use BookStack\Services\RestrictionService; use Setting; class PermissionsRepo @@ -11,16 +12,19 @@ class PermissionsRepo protected $permission; protected $role; + protected $restrictionService; /** * PermissionsRepo constructor. - * @param $permission - * @param $role + * @param Permission $permission + * @param Role $role + * @param RestrictionService $restrictionService */ - public function __construct(Permission $permission, Role $role) + public function __construct(Permission $permission, Role $role, RestrictionService $restrictionService) { $this->permission = $permission; $this->role = $role; + $this->restrictionService = $restrictionService; } /** @@ -69,6 +73,7 @@ class PermissionsRepo $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : []; $this->assignRolePermissions($role, $permissions); + $this->restrictionService->buildEntityPermissionForRole($role); return $role; } @@ -91,6 +96,7 @@ class PermissionsRepo $role->fill($roleData); $role->save(); + $this->restrictionService->buildEntityPermissionForRole($role); } /** @@ -136,6 +142,7 @@ class PermissionsRepo } } + $this->restrictionService->deleteEntityPermissionsForRole($role); $role->delete(); } diff --git a/app/Role.php b/app/Role.php index 4e14db181..45d160cfe 100644 --- a/app/Role.php +++ b/app/Role.php @@ -17,6 +17,15 @@ class Role extends Model return $this->belongsToMany('BookStack\User'); } + /** + * Get all related entity permissions. + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function entityPermissions() + { + return $this->hasMany(EntityPermission::class); + } + /** * The permissions that belong to the role. */ diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php index d0029b6c4..54e922667 100644 --- a/app/Services/ActivityService.php +++ b/app/Services/ActivityService.php @@ -105,8 +105,16 @@ class ActivityService */ public function entityActivity($entity, $count = 20, $page = 0) { - $activity = $entity->hasMany('BookStack\Activity')->orderBy('created_at', 'desc') - ->skip($count * $page)->take($count)->get(); + if ($entity->isA('book')) { + $query = $this->activity->where('book_id', '=', $entity->id); + } else { + $query = $this->activity->where('entity_type', '=', get_class($entity)) + ->where('entity_id', '=', $entity->id); + } + + $activity = $this->restrictionService + ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type') + ->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get(); return $this->filterSimilar($activity); } diff --git a/app/Services/RestrictionService.php b/app/Services/RestrictionService.php index 847db29fe..0050401bf 100644 --- a/app/Services/RestrictionService.php +++ b/app/Services/RestrictionService.php @@ -23,11 +23,14 @@ class RestrictionService protected $entityPermission; protected $role; + /** + * The actions that have permissions attached throughout the application. + * @var array + */ protected $actions = ['view', 'create', 'update', 'delete']; /** * RestrictionService constructor. - * TODO - Handle events when roles or entities change. * @param EntityPermission $entityPermission * @param Book $book * @param Chapter $chapter @@ -73,6 +76,92 @@ class RestrictionService }); } + /** + * Create the entity permissions for a particular entity. + * @param Entity $entity + */ + public function buildEntityPermissionsForEntity(Entity $entity) + { + $roles = $this->role->load('permissions')->all(); + $entities = collect([$entity]); + + if ($entity->isA('book')) { + $entities = $entities->merge($entity->chapters); + $entities = $entities->merge($entity->pages); + } elseif ($entity->isA('chapter')) { + $entities = $entities->merge($entity->pages); + } + + $this->deleteManyEntityPermissionsForEntities($entities); + $this->createManyEntityPermissions($entities, $roles); + } + + /** + * Build the entity permissions for a particular role. + * @param Role $role + */ + public function buildEntityPermissionForRole(Role $role) + { + $roles = collect([$role]); + + $this->deleteManyEntityPermissionsForRoles($roles); + + // Chunk through all books + $this->book->chunk(500, function ($books) use ($roles) { + $this->createManyEntityPermissions($books, $roles); + }); + + // Chunk through all chapters + $this->chapter->with('book')->chunk(500, function ($books) use ($roles) { + $this->createManyEntityPermissions($books, $roles); + }); + + // Chunk through all pages + $this->page->with('book', 'chapter')->chunk(500, function ($books) use ($roles) { + $this->createManyEntityPermissions($books, $roles); + }); + } + + /** + * Delete the entity permissions attached to a particular role. + * @param Role $role + */ + public function deleteEntityPermissionsForRole(Role $role) + { + $this->deleteManyEntityPermissionsForRoles([$role]); + } + + /** + * Delete all of the entity permissions for a list of entities. + * @param Role[] $roles + */ + protected function deleteManyEntityPermissionsForRoles($roles) + { + foreach ($roles as $role) { + $role->entityPermissions()->delete(); + } + } + + /** + * Delete the entity permissions for a particular entity. + * @param Entity $entity + */ + public function deleteEntityPermissionsForEntity(Entity $entity) + { + $this->deleteManyEntityPermissionsForEntities([$entity]); + } + + /** + * Delete all of the entity permissions for a list of entities. + * @param Entity[] $entities + */ + protected function deleteManyEntityPermissionsForEntities($entities) + { + foreach ($entities as $entity) { + $entity->permissions()->delete(); + } + } + /** * Create & Save entity permissions for many entities and permissions. * @param Collection $entities @@ -88,10 +177,18 @@ class RestrictionService } } } + \Log::info(collect($entityPermissions)->where('entity_id', 1)->where('entity_type', 'BookStack\\Page')->where('role_id', 2)->all()); $this->entityPermission->insert($entityPermissions); } - + /** + * Create entity permission data for an entity and role + * for a particular action. + * @param Entity $entity + * @param Role $role + * @param $action + * @return array + */ protected function createEntityPermissionData(Entity $entity, Role $role, $action) { $permissionPrefix = $entity->getType() . '-' . $action; @@ -103,29 +200,39 @@ class RestrictionService if (!$entity->restricted) { return $this->createEntityPermissionDataArray($entity, $role, $action, $roleHasPermission, $roleHasPermissionOwn); } else { - $hasAccess = $entity->hasRestriction($role->id, $action); + $hasAccess = $entity->hasActiveRestriction($role->id, $action); return $this->createEntityPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess); } } elseif ($entity->isA('chapter')) { if (!$entity->restricted) { - $hasAccessToBook = $entity->book->hasRestriction($role->id, $action); + $hasExplicitAccessToBook = $entity->book->hasActiveRestriction($role->id, $action); + $hasPermissiveAccessToBook = !$entity->book->restricted; return $this->createEntityPermissionDataArray($entity, $role, $action, - ($roleHasPermission && $hasAccessToBook), ($roleHasPermissionOwn && $hasAccessToBook)); + ($hasExplicitAccessToBook || ($roleHasPermission && $hasPermissiveAccessToBook)), + ($hasExplicitAccessToBook || ($roleHasPermissionOwn && $hasPermissiveAccessToBook))); } else { - $hasAccess = $entity->hasRestriction($role->id, $action); + $hasAccess = $entity->hasActiveRestriction($role->id, $action); return $this->createEntityPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess); } } elseif ($entity->isA('page')) { if (!$entity->restricted) { - $hasAccessToBook = $entity->book->hasRestriction($role->id, $action); - $hasAccessToChapter = $entity->chapter ? ($entity->chapter->hasRestriction($role->id, $action)) : true; + $hasExplicitAccessToBook = $entity->book->hasActiveRestriction($role->id, $action); + $hasPermissiveAccessToBook = !$entity->book->restricted; + $hasExplicitAccessToChapter = $entity->chapter && $entity->chapter->hasActiveRestriction($role->id, $action); + $hasPermissiveAccessToChapter = $entity->chapter && !$entity->chapter->restricted; + $acknowledgeChapter = ($entity->chapter && $entity->chapter->restricted); + + $hasExplicitAccessToParents = $acknowledgeChapter ? $hasExplicitAccessToChapter : $hasExplicitAccessToBook; + $hasPermissiveAccessToParents = $acknowledgeChapter ? $hasPermissiveAccessToChapter : $hasPermissiveAccessToBook; + return $this->createEntityPermissionDataArray($entity, $role, $action, - ($roleHasPermission && $hasAccessToBook && $hasAccessToChapter), - ($roleHasPermissionOwn && $hasAccessToBook && $hasAccessToChapter)); + ($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)), + ($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents)) + ); } else { $hasAccess = $entity->hasRestriction($role->id, $action); return $this->createEntityPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess); @@ -134,6 +241,16 @@ class RestrictionService } } + /** + * Create an array of data with the information of an entity permissions. + * Used to build data for bulk insertion. + * @param Entity $entity + * @param Role $role + * @param $action + * @param $permissionAll + * @param $permissionOwn + * @return array + */ protected function createEntityPermissionDataArray(Entity $entity, Role $role, $action, $permissionAll, $permissionOwn) { $entityClass = get_class($entity); @@ -151,22 +268,30 @@ class RestrictionService /** * Checks if an entity has a restriction set upon it. * @param Entity $entity - * @param $action + * @param $permission * @return bool */ - public function checkIfEntityRestricted(Entity $entity, $action) + public function checkEntityUserAccess(Entity $entity, $permission) { if ($this->isAdmin) return true; - $this->currentAction = $action; + $explodedPermission = explode('-', $permission); + $baseQuery = $entity->where('id', '=', $entity->id); - if ($entity->isA('page')) { - return $this->pageRestrictionQuery($baseQuery)->count() > 0; - } elseif ($entity->isA('chapter')) { - return $this->chapterRestrictionQuery($baseQuery)->count() > 0; - } elseif ($entity->isA('book')) { - return $this->bookRestrictionQuery($baseQuery)->count() > 0; + + $nonEntityPermissions = ['restrictions']; + + // Handle non entity specific permissions + if (in_array($explodedPermission[0], $nonEntityPermissions)) { + $allPermission = $this->currentUser && $this->currentUser->can($permission . '-all'); + $ownPermission = $this->currentUser && $this->currentUser->can($permission . '-own'); + $this->currentAction = 'view'; + $isOwner = $this->currentUser && $this->currentUser->id === $entity->created_by; + return ($allPermission || ($isOwner && $ownPermission)); } - return false; + + $action = end($explodedPermission); + $this->currentAction = $action; + return $this->entityRestrictionQuery($baseQuery)->count() > 0; } /** @@ -188,29 +313,6 @@ class RestrictionService } } - /** - * Add restrictions for a page query - * @param $query - * @param string $action - * @return mixed - */ - public function enforcePageRestrictions($query, $action = 'view') - { - // Prevent drafts being visible to others. - $query = $query->where(function ($query) { - $query->where('draft', '=', false); - if ($this->currentUser) { - $query->orWhere(function ($query) { - $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser->id); - }); - } - }); - - if ($this->isAdmin) return $query; - $this->currentAction = $action; - return $this->entityRestrictionQuery($query); - } - /** * The general query filter to remove all entities * that the current user does not have access to. @@ -234,6 +336,29 @@ class RestrictionService }); } + /** + * Add restrictions for a page query + * @param $query + * @param string $action + * @return mixed + */ + public function enforcePageRestrictions($query, $action = 'view') + { + // Prevent drafts being visible to others. + $query = $query->where(function ($query) { + $query->where('draft', '=', false); + if ($this->currentUser) { + $query->orWhere(function ($query) { + $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser->id); + }); + } + }); + + if ($this->isAdmin) return $query; + $this->currentAction = $action; + return $this->entityRestrictionQuery($query); + } + /** * Add on permission restrictions to a chapter query. * @param $query @@ -316,7 +441,7 @@ class RestrictionService ->where(function ($query) { $query->where('has_permission', '=', true)->orWhere(function ($query) { $query->where('has_permission_own', '=', true) - ->where('created_by', '=', $this->currentUser->id); + ->where('created_by', '=', $this->currentUser ? $this->currentUser->id : 0); }); }); }); diff --git a/app/helpers.php b/app/helpers.php index eab8ca1c8..582e4e03a 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -45,20 +45,8 @@ function userCan($permission, \BookStack\Ownable $ownable = null) } // Check permission on ownable item - $permissionBaseName = strtolower($permission) . '-'; - $hasPermission = false; - if (auth()->user()->can($permissionBaseName . 'all')) $hasPermission = true; - if (auth()->user()->can($permissionBaseName . 'own') && $ownable->createdBy && $ownable->createdBy->id === auth()->user()->id) $hasPermission = true; - - if (!$ownable instanceof \BookStack\Entity) return $hasPermission; - - // Check restrictions on the entity $restrictionService = app('BookStack\Services\RestrictionService'); - $explodedPermission = explode('-', $permission); - $action = end($explodedPermission); - $hasAccess = $restrictionService->checkIfEntityRestricted($ownable, $action); - $restrictionsSet = $restrictionService->checkIfRestrictionsSet($ownable, $action); - return ($hasAccess && $restrictionsSet) || (!$restrictionsSet && $hasPermission); + return $restrictionService->checkEntityUserAccess($ownable, $permission); } /** diff --git a/database/migrations/2016_04_09_100730_add_view_permissions_to_roles.php b/database/migrations/2016_04_09_100730_add_view_permissions_to_roles.php index dabd6a25e..b97a3d09b 100644 --- a/database/migrations/2016_04_09_100730_add_view_permissions_to_roles.php +++ b/database/migrations/2016_04_09_100730_add_view_permissions_to_roles.php @@ -23,6 +23,7 @@ class AddViewPermissionsToRoles extends Migration $newPermission->name = strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op)); $newPermission->display_name = $op . ' ' . $entity . 's'; $newPermission->save(); + // Assign view permissions to all current roles foreach ($currentRoles as $role) { $role->attachPermission($newPermission); } diff --git a/tests/Permissions/RestrictionsTest.php b/tests/Permissions/RestrictionsTest.php index 4ecf5fb20..0aa1389a6 100644 --- a/tests/Permissions/RestrictionsTest.php +++ b/tests/Permissions/RestrictionsTest.php @@ -4,12 +4,14 @@ class RestrictionsTest extends TestCase { protected $user; protected $viewer; + protected $restrictionService; public function setUp() { parent::setUp(); $this->user = $this->getNewUser(); $this->viewer = $this->getViewer(); + $this->restrictionService = $this->app[\BookStack\Services\RestrictionService::class]; } protected function getViewer() @@ -43,6 +45,8 @@ class RestrictionsTest extends TestCase } $entity->save(); $entity->load('restrictions'); + $this->restrictionService->buildEntityPermissionsForEntity($entity); + $entity->load('permissions'); } public function test_book_view_restriction() diff --git a/tests/Permissions/RolesTest.php b/tests/Permissions/RolesTest.php index 8ecdb37a3..84169c90b 100644 --- a/tests/Permissions/RolesTest.php +++ b/tests/Permissions/RolesTest.php @@ -7,7 +7,15 @@ class RolesTest extends TestCase public function setUp() { parent::setUp(); - $this->user = $this->getNewBlankUser(); + $this->user = $this->getViewer(); + } + + protected function getViewer() + { + $role = \BookStack\Role::getRole('viewer'); + $viewer = $this->getNewBlankUser(); + $viewer->attachRole($role);; + return $viewer; } /** @@ -141,7 +149,7 @@ class RolesTest extends TestCase public function test_restrictions_manage_own_permission() { - $otherUsersPage = \BookStack\Page::take(1)->get()->first(); + $otherUsersPage = \BookStack\Page::first(); $content = $this->createEntityChainBelongingToUser($this->user); // Check can't restrict other's content $this->actingAs($this->user)->visit($otherUsersPage->getUrl()) diff --git a/tests/TestCase.php b/tests/TestCase.php index f46d73e04..1b6a69c62 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -65,6 +65,8 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase $page = factory(BookStack\Page::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id, 'book_id' => $book->id]); $book->chapters()->saveMany([$chapter]); $chapter->pages()->saveMany([$page]); + $restrictionService = $this->app[\BookStack\Services\RestrictionService::class]; + $restrictionService->buildEntityPermissionsForEntity($book); return [ 'book' => $book, 'chapter' => $chapter,