diff --git a/app/Http/routes.php b/app/Http/routes.php
index 0be901231..eca37347c 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -19,8 +19,8 @@ Route::group(['middleware' => 'auth'], function () {
Route::delete('/{id}', 'BookController@destroy');
Route::get('/{slug}/sort-item', 'BookController@getSortItem');
Route::get('/{slug}', 'BookController@show');
- Route::get('/{bookSlug}/restrict', 'BookController@showRestrict');
- Route::put('/{bookSlug}/restrict', 'BookController@restrict');
+ Route::get('/{bookSlug}/permissions', 'BookController@showRestrict');
+ Route::put('/{bookSlug}/permissions', 'BookController@restrict');
Route::get('/{slug}/delete', 'BookController@showDelete');
Route::get('/{bookSlug}/sort', 'BookController@sort');
Route::put('/{bookSlug}/sort', 'BookController@saveSort');
@@ -36,8 +36,8 @@ Route::group(['middleware' => 'auth'], function () {
Route::get('/{bookSlug}/page/{pageSlug}/edit', 'PageController@edit');
Route::get('/{bookSlug}/page/{pageSlug}/delete', 'PageController@showDelete');
Route::get('/{bookSlug}/draft/{pageId}/delete', 'PageController@showDeleteDraft');
- Route::get('/{bookSlug}/page/{pageSlug}/restrict', 'PageController@showRestrict');
- Route::put('/{bookSlug}/page/{pageSlug}/restrict', 'PageController@restrict');
+ Route::get('/{bookSlug}/page/{pageSlug}/permissions', 'PageController@showRestrict');
+ Route::put('/{bookSlug}/page/{pageSlug}/permissions', 'PageController@restrict');
Route::put('/{bookSlug}/page/{pageSlug}', 'PageController@update');
Route::delete('/{bookSlug}/page/{pageSlug}', 'PageController@destroy');
Route::delete('/{bookSlug}/draft/{pageId}', 'PageController@destroyDraft');
@@ -54,8 +54,8 @@ Route::group(['middleware' => 'auth'], function () {
Route::get('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@show');
Route::put('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@update');
Route::get('/{bookSlug}/chapter/{chapterSlug}/edit', 'ChapterController@edit');
- Route::get('/{bookSlug}/chapter/{chapterSlug}/restrict', 'ChapterController@showRestrict');
- Route::put('/{bookSlug}/chapter/{chapterSlug}/restrict', 'ChapterController@restrict');
+ Route::get('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@showRestrict');
+ Route::put('/{bookSlug}/chapter/{chapterSlug}/permissions', 'ChapterController@restrict');
Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');
Route::delete('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@destroy');
diff --git a/app/Services/RestrictionService.php b/app/Services/RestrictionService.php
index d20724866..50cbe4a51 100644
--- a/app/Services/RestrictionService.php
+++ b/app/Services/RestrictionService.php
@@ -41,6 +41,25 @@ class RestrictionService
return false;
}
+ /**
+ * Check if an entity has restrictions set on itself or its
+ * parent tree.
+ * @param Entity $entity
+ * @param $action
+ * @return bool|mixed
+ */
+ public function checkIfRestrictionsSet(Entity $entity, $action)
+ {
+ $this->currentAction = $action;
+ if ($entity->isA('page')) {
+ return $entity->restricted || ($entity->chapter && $entity->chapter->restricted) || $entity->book->restricted;
+ } elseif ($entity->isA('chapter')) {
+ return $entity->restricted || $entity->book->restricted;
+ } elseif ($entity->isA('book')) {
+ return $entity->restricted;
+ }
+ }
+
/**
* Add restrictions for a page query
* @param $query
diff --git a/app/helpers.php b/app/helpers.php
index f60e917c5..eab8ca1c8 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -52,12 +52,13 @@ function userCan($permission, \BookStack\Ownable $ownable = null)
if (!$ownable instanceof \BookStack\Entity) return $hasPermission;
- // Check restrictions on the entitiy
+ // Check restrictions on the entity
$restrictionService = app('BookStack\Services\RestrictionService');
$explodedPermission = explode('-', $permission);
$action = end($explodedPermission);
$hasAccess = $restrictionService->checkIfEntityRestricted($ownable, $action);
- return $hasAccess && $hasPermission;
+ $restrictionsSet = $restrictionService->checkIfRestrictionsSet($ownable, $action);
+ return ($hasAccess && $restrictionsSet) || (!$restrictionsSet && $hasPermission);
}
/**
diff --git a/resources/views/books/restrictions.blade.php b/resources/views/books/restrictions.blade.php
index 60b126a7b..7fdd3abef 100644
--- a/resources/views/books/restrictions.blade.php
+++ b/resources/views/books/restrictions.blade.php
@@ -16,7 +16,7 @@
-
Book Restrictions
+ Book Permissions
@include('form/restriction-form', ['model' => $book])
diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php
index cd32a406b..5f8067bfb 100644
--- a/resources/views/books/show.blade.php
+++ b/resources/views/books/show.blade.php
@@ -24,7 +24,7 @@
Sort
@endif
@if(userCan('restrictions-manage', $book))
- Restrict
+ Permissions
@endif
@if(userCan('book-delete', $book))
Delete
@@ -90,9 +90,9 @@
@if($book->restricted)
@if(userCan('restrictions-manage', $book))
- Book Restricted
+ Book Permissions Active
@else
- Book Restricted
+ Book Permissions Active
@endif
@endif
diff --git a/resources/views/chapters/restrictions.blade.php b/resources/views/chapters/restrictions.blade.php
index 1f2f9c8fa..c25c0755d 100644
--- a/resources/views/chapters/restrictions.blade.php
+++ b/resources/views/chapters/restrictions.blade.php
@@ -17,7 +17,7 @@
-
Chapter Restrictions
+ Chapter Permissions
@include('form/restriction-form', ['model' => $chapter])
diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php
index dc20d144e..b6b2d5c97 100644
--- a/resources/views/chapters/show.blade.php
+++ b/resources/views/chapters/show.blade.php
@@ -19,7 +19,7 @@
Edit
@endif
@if(userCan('restrictions-manage', $chapter))
- Restrict
+ Permissions
@endif
@if(userCan('chapter-delete', $chapter))
Delete
@@ -69,18 +69,18 @@
@if($book->restricted)
@if(userCan('restrictions-manage', $book))
- Book Restricted
+ Book Permissions Active
@else
- Book Restricted
+ Book Permissions Active
@endif
@endif
@if($chapter->restricted)
@if(userCan('restrictions-manage', $chapter))
- Chapter Restricted
+ Chapter Permissions Active
@else
- Chapter Restricted
+ Chapter Permissions Active
@endif
@endif
diff --git a/resources/views/form/restriction-form.blade.php b/resources/views/form/restriction-form.blade.php
index d2fa23982..f61a535e7 100644
--- a/resources/views/form/restriction-form.blade.php
+++ b/resources/views/form/restriction-form.blade.php
@@ -1,11 +1,14 @@
-
\ No newline at end of file
diff --git a/resources/views/pages/restrictions.blade.php b/resources/views/pages/restrictions.blade.php
index d094abc71..09eb8a65b 100644
--- a/resources/views/pages/restrictions.blade.php
+++ b/resources/views/pages/restrictions.blade.php
@@ -24,7 +24,7 @@
-
Page Restrictions
+ Page Permissions
@include('form/restriction-form', ['model' => $page])
diff --git a/resources/views/pages/show.blade.php b/resources/views/pages/show.blade.php
index 286d44387..8640a34db 100644
--- a/resources/views/pages/show.blade.php
+++ b/resources/views/pages/show.blade.php
@@ -32,7 +32,7 @@
Edit
@endif
@if(userCan('restrictions-manage', $page))
- Restrict
+ Permissions
@endif
@if(userCan('page-delete', $page))
Delete
@@ -76,27 +76,27 @@
@if($book->restricted)
@if(userCan('restrictions-manage', $book))
- Book restricted
+ Book Permissions Active
@else
- Book restricted
+ Book Permissions Active
@endif
@endif
@if($page->chapter && $page->chapter->restricted)
@if(userCan('restrictions-manage', $page->chapter))
- Chapter restricted
+ Chapter Permissions Active
@else
- Chapter restricted
+ Chapter Permissions Active
@endif
@endif
@if($page->restricted)
@if(userCan('restrictions-manage', $page))
- Page restricted
+ Page Permissions Active
@else
- Page restricted
+ Page Permissions Active
@endif
@endif
diff --git a/resources/views/settings/roles/form.blade.php b/resources/views/settings/roles/form.blade.php
index fafb9bed2..ba57b4daa 100644
--- a/resources/views/settings/roles/form.blade.php
+++ b/resources/views/settings/roles/form.blade.php
@@ -24,10 +24,10 @@
- @include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) Manage all restrictions
+ @include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) Manage all Book, Chapter & Page permissions
- @include('settings/roles/checkbox', ['permission' => 'restrictions-manage-own']) Manage restrictions on own content
+ @include('settings/roles/checkbox', ['permission' => 'restrictions-manage-own']) Manage permissions on own Book, Chapter & Pages
@@ -43,7 +43,7 @@
Asset Permissions
These permissions control default access to the assets within the system.
- Restrictions on Books, Chapters and Pages will override these permissions.
+ Permissions on Books, Chapters and Pages will override these permissions.
diff --git a/resources/views/users/delete.blade.php b/resources/views/users/delete.blade.php
index 282ae242b..af247509d 100644
--- a/resources/views/users/delete.blade.php
+++ b/resources/views/users/delete.blade.php
@@ -10,7 +10,7 @@
diff --git a/tests/Permissions/RestrictionsTest.php b/tests/Permissions/RestrictionsTest.php
index 40b5a7647..4ecf5fb20 100644
--- a/tests/Permissions/RestrictionsTest.php
+++ b/tests/Permissions/RestrictionsTest.php
@@ -3,11 +3,21 @@
class RestrictionsTest extends TestCase
{
protected $user;
+ protected $viewer;
public function setUp()
{
parent::setUp();
$this->user = $this->getNewUser();
+ $this->viewer = $this->getViewer();
+ }
+
+ protected function getViewer()
+ {
+ $role = \BookStack\Role::getRole('viewer');
+ $viewer = $this->getNewBlankUser();
+ $viewer->attachRole($role);;
+ return $viewer;
}
/**
@@ -20,11 +30,16 @@ class RestrictionsTest extends TestCase
$entity->restricted = true;
$entity->restrictions()->delete();
$role = $this->user->roles->first();
+ $viewerRole = $this->viewer->roles->first();
foreach ($actions as $action) {
$entity->restrictions()->create([
'role_id' => $role->id,
'action' => strtolower($action)
]);
+ $entity->restrictions()->create([
+ 'role_id' => $viewerRole->id,
+ 'action' => strtolower($action)
+ ]);
}
$entity->save();
$entity->load('restrictions');
@@ -65,6 +80,10 @@ class RestrictionsTest extends TestCase
$book = \BookStack\Book::first();
$bookUrl = $book->getUrl();
+ $this->actingAs($this->viewer)
+ ->visit($bookUrl)
+ ->dontSeeInElement('.action-buttons', 'New Page')
+ ->dontSeeInElement('.action-buttons', 'New Chapter');
$this->actingAs($this->user)
->visit($bookUrl)
->seeInElement('.action-buttons', 'New Page')
@@ -319,11 +338,11 @@ class RestrictionsTest extends TestCase
public function test_book_restriction_form()
{
$book = \BookStack\Book::first();
- $this->asAdmin()->visit($book->getUrl() . '/restrict')
- ->see('Book Restrictions')
+ $this->asAdmin()->visit($book->getUrl() . '/permissions')
+ ->see('Book Permissions')
->check('restricted')
->check('restrictions[2][view]')
- ->press('Save Restrictions')
+ ->press('Save Permissions')
->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
->seeInDatabase('restrictions', [
'restrictable_id' => $book->id,
@@ -336,11 +355,11 @@ class RestrictionsTest extends TestCase
public function test_chapter_restriction_form()
{
$chapter = \BookStack\Chapter::first();
- $this->asAdmin()->visit($chapter->getUrl() . '/restrict')
- ->see('Chapter Restrictions')
+ $this->asAdmin()->visit($chapter->getUrl() . '/permissions')
+ ->see('Chapter Permissions')
->check('restricted')
->check('restrictions[2][update]')
- ->press('Save Restrictions')
+ ->press('Save Permissions')
->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
->seeInDatabase('restrictions', [
'restrictable_id' => $chapter->id,
@@ -353,11 +372,11 @@ class RestrictionsTest extends TestCase
public function test_page_restriction_form()
{
$page = \BookStack\Page::first();
- $this->asAdmin()->visit($page->getUrl() . '/restrict')
- ->see('Page Restrictions')
+ $this->asAdmin()->visit($page->getUrl() . '/permissions')
+ ->see('Page Permissions')
->check('restricted')
->check('restrictions[2][delete]')
- ->press('Save Restrictions')
+ ->press('Save Permissions')
->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
->seeInDatabase('restrictions', [
'restrictable_id' => $page->id,
@@ -404,4 +423,99 @@ class RestrictionsTest extends TestCase
->dontSee($page->name);
}
+ public function test_book_create_restriction_override()
+ {
+ $book = \BookStack\Book::first();
+
+ $bookUrl = $book->getUrl();
+ $this->actingAs($this->viewer)
+ ->visit($bookUrl)
+ ->dontSeeInElement('.action-buttons', 'New Page')
+ ->dontSeeInElement('.action-buttons', 'New Chapter');
+
+ $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
+
+ $this->forceVisit($bookUrl . '/chapter/create')
+ ->see('You do not have permission')->seePageIs('/');
+ $this->forceVisit($bookUrl . '/page/create')
+ ->see('You do not have permission')->seePageIs('/');
+ $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
+ ->dontSeeInElement('.action-buttons', 'New Chapter');
+
+ $this->setEntityRestrictions($book, ['view', 'create']);
+
+ $this->visit($bookUrl . '/chapter/create')
+ ->type('test chapter', 'name')
+ ->type('test description for chapter', 'description')
+ ->press('Save Chapter')
+ ->seePageIs($bookUrl . '/chapter/test-chapter');
+ $this->visit($bookUrl . '/page/create')
+ ->type('test page', 'name')
+ ->type('test content', 'html')
+ ->press('Save Page')
+ ->seePageIs($bookUrl . '/page/test-page');
+ $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
+ ->seeInElement('.action-buttons', 'New Chapter');
+ }
+
+ public function test_book_update_restriction_override()
+ {
+ $book = \BookStack\Book::first();
+ $bookPage = $book->pages->first();
+ $bookChapter = $book->chapters->first();
+
+ $bookUrl = $book->getUrl();
+ $this->actingAs($this->viewer)
+ ->visit($bookUrl . '/edit')
+ ->dontSee('Edit Book');
+
+ $this->setEntityRestrictions($book, ['view', 'delete']);
+
+ $this->forceVisit($bookUrl . '/edit')
+ ->see('You do not have permission')->seePageIs('/');
+ $this->forceVisit($bookPage->getUrl() . '/edit')
+ ->see('You do not have permission')->seePageIs('/');
+ $this->forceVisit($bookChapter->getUrl() . '/edit')
+ ->see('You do not have permission')->seePageIs('/');
+
+ $this->setEntityRestrictions($book, ['view', 'update']);
+
+ $this->visit($bookUrl . '/edit')
+ ->seePageIs($bookUrl . '/edit');
+ $this->visit($bookPage->getUrl() . '/edit')
+ ->seePageIs($bookPage->getUrl() . '/edit');
+ $this->visit($bookChapter->getUrl() . '/edit')
+ ->see('Edit Chapter');
+ }
+
+ public function test_book_delete_restriction_override()
+ {
+ $book = \BookStack\Book::first();
+ $bookPage = $book->pages->first();
+ $bookChapter = $book->chapters->first();
+
+ $bookUrl = $book->getUrl();
+ $this->actingAs($this->viewer)
+ ->visit($bookUrl . '/delete')
+ ->dontSee('Delete Book');
+
+ $this->setEntityRestrictions($book, ['view', 'update']);
+
+ $this->forceVisit($bookUrl . '/delete')
+ ->see('You do not have permission')->seePageIs('/');
+ $this->forceVisit($bookPage->getUrl() . '/delete')
+ ->see('You do not have permission')->seePageIs('/');
+ $this->forceVisit($bookChapter->getUrl() . '/delete')
+ ->see('You do not have permission')->seePageIs('/');
+
+ $this->setEntityRestrictions($book, ['view', 'delete']);
+
+ $this->visit($bookUrl . '/delete')
+ ->seePageIs($bookUrl . '/delete')->see('Delete Book');
+ $this->visit($bookPage->getUrl() . '/delete')
+ ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
+ $this->visit($bookChapter->getUrl() . '/delete')
+ ->see('Delete Chapter');
+ }
+
}
diff --git a/tests/Permissions/RolesTest.php b/tests/Permissions/RolesTest.php
index 9c312626f..8ecdb37a3 100644
--- a/tests/Permissions/RolesTest.php
+++ b/tests/Permissions/RolesTest.php
@@ -129,14 +129,14 @@ class RolesTest extends TestCase
{
$page = \BookStack\Page::take(1)->get()->first();
$this->actingAs($this->user)->visit($page->getUrl())
- ->dontSee('Restrict')
- ->visit($page->getUrl() . '/restrict')
+ ->dontSee('Permissions')
+ ->visit($page->getUrl() . '/permissions')
->seePageIs('/');
$this->giveUserPermissions($this->user, ['restrictions-manage-all']);
$this->actingAs($this->user)->visit($page->getUrl())
- ->see('Restrict')
- ->click('Restrict')
- ->see('Page Restrictions')->seePageIs($page->getUrl() . '/restrict');
+ ->see('Permissions')
+ ->click('Permissions')
+ ->see('Page Permissions')->seePageIs($page->getUrl() . '/permissions');
}
public function test_restrictions_manage_own_permission()
@@ -145,27 +145,27 @@ class RolesTest extends TestCase
$content = $this->createEntityChainBelongingToUser($this->user);
// Check can't restrict other's content
$this->actingAs($this->user)->visit($otherUsersPage->getUrl())
- ->dontSee('Restrict')
- ->visit($otherUsersPage->getUrl() . '/restrict')
+ ->dontSee('Permissions')
+ ->visit($otherUsersPage->getUrl() . '/permissions')
->seePageIs('/');
// Check can't restrict own content
$this->actingAs($this->user)->visit($content['page']->getUrl())
- ->dontSee('Restrict')
- ->visit($content['page']->getUrl() . '/restrict')
+ ->dontSee('Permissions')
+ ->visit($content['page']->getUrl() . '/permissions')
->seePageIs('/');
$this->giveUserPermissions($this->user, ['restrictions-manage-own']);
// Check can't restrict other's content
$this->actingAs($this->user)->visit($otherUsersPage->getUrl())
- ->dontSee('Restrict')
- ->visit($otherUsersPage->getUrl() . '/restrict')
+ ->dontSee('Permissions')
+ ->visit($otherUsersPage->getUrl() . '/permissions')
->seePageIs('/');
// Check can restrict own content
$this->actingAs($this->user)->visit($content['page']->getUrl())
- ->see('Restrict')
- ->click('Restrict')
- ->seePageIs($content['page']->getUrl() . '/restrict');
+ ->see('Permissions')
+ ->click('Permissions')
+ ->seePageIs($content['page']->getUrl() . '/permissions');
}
/**
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 567dc93ec..d3b41831e 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -170,4 +170,12 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
$this->visit($link->link()->getUri());
return $this;
}
+
+ protected function actingAsUsers($usersArray, $callback)
+ {
+ foreach ($usersArray as $user) {
+ $this->actingAs($user);
+ $callback($user);
+ }
+ }
}