-<?php
+<?php namespace Tests\Permissions;
-class RestrictionsTest extends TestCase
+use BookStack\Entities\Book;
+use BookStack\Entities\Bookshelf;
+use BookStack\Entities\Chapter;
+use BookStack\Entities\Entity;
+use BookStack\Auth\User;
+use BookStack\Entities\Page;
+use Tests\BrowserKitTest;
+
+class RestrictionsTest extends BrowserKitTest
{
+
+ /**
+ * @var User
+ */
protected $user;
+
+ /**
+ * @var User
+ */
protected $viewer;
- protected $restrictionService;
- public function setUp()
+ public function setUp(): void
{
parent::setUp();
- $this->user = $this->getNewUser();
+ $this->user = $this->getEditor();
$this->viewer = $this->getViewer();
- $this->restrictionService = $this->app[\BookStack\Services\RestrictionService::class];
}
- protected function getViewer()
+ protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = [])
{
- $role = \BookStack\Role::getRole('viewer');
- $viewer = $this->getNewBlankUser();
- $viewer->attachRole($role);;
- return $viewer;
+ $roles = [
+ $this->user->roles->first(),
+ $this->viewer->roles->first(),
+ ];
+ parent::setEntityRestrictions($entity, $actions, $roles);
}
- /**
- * Manually set some restrictions on an entity.
- * @param \BookStack\Entity $entity
- * @param $actions
- */
- protected function setEntityRestrictions(\BookStack\Entity $entity, $actions)
+ public function test_bookshelf_view_restriction()
{
- $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');
- $this->restrictionService->buildEntityPermissionsForEntity($entity);
- $entity->load('permissions');
+ $shelf = Bookshelf::first();
+
+ $this->actingAs($this->user)
+ ->visit($shelf->getUrl())
+ ->seePageIs($shelf->getUrl());
+
+ $this->setEntityRestrictions($shelf, []);
+
+ $this->forceVisit($shelf->getUrl())
+ ->see('Bookshelf not found');
+
+ $this->setEntityRestrictions($shelf, ['view']);
+
+ $this->visit($shelf->getUrl())
+ ->see($shelf->name);
+ }
+
+ public function test_bookshelf_update_restriction()
+ {
+ $shelf = BookShelf::first();
+
+ $this->actingAs($this->user)
+ ->visit($shelf->getUrl('/edit'))
+ ->see('Edit Book');
+
+ $this->setEntityRestrictions($shelf, ['view', 'delete']);
+
+ $this->forceVisit($shelf->getUrl('/edit'))
+ ->see('You do not have permission')->seePageIs('/');
+
+ $this->setEntityRestrictions($shelf, ['view', 'update']);
+
+ $this->visit($shelf->getUrl('/edit'))
+ ->seePageIs($shelf->getUrl('/edit'));
+ }
+
+ public function test_bookshelf_delete_restriction()
+ {
+ $shelf = Book::first();
+
+ $this->actingAs($this->user)
+ ->visit($shelf->getUrl('/delete'))
+ ->see('Delete Book');
+
+ $this->setEntityRestrictions($shelf, ['view', 'update']);
+
+ $this->forceVisit($shelf->getUrl('/delete'))
+ ->see('You do not have permission')->seePageIs('/');
+
+ $this->setEntityRestrictions($shelf, ['view', 'delete']);
+
+ $this->visit($shelf->getUrl('/delete'))
+ ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
}
public function test_book_view_restriction()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookPage = $book->pages->first();
$bookChapter = $book->chapters->first();
$this->forceVisit($bookUrl)
->see('Book not found');
$this->forceVisit($bookPage->getUrl())
- ->see('Book not found');
+ ->see('Page not found');
$this->forceVisit($bookChapter->getUrl())
- ->see('Book not found');
+ ->see('Chapter not found');
$this->setEntityRestrictions($book, ['view']);
public function test_book_create_restriction()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookUrl = $book->getUrl();
$this->actingAs($this->viewer)
->visit($bookUrl)
- ->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ ->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->actingAs($this->user)
->visit($bookUrl)
- ->seeInElement('.action-buttons', 'New Page')
- ->seeInElement('.action-buttons', 'New Chapter');
+ ->seeInElement('.actions', 'New Page')
+ ->seeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'delete', 'update']);
- $this->forceVisit($bookUrl . '/chapter/create')
+ $this->forceVisit($bookUrl . '/create-chapter')
->see('You do not have permission')->seePageIs('/');
- $this->forceVisit($bookUrl . '/page/create')
+ $this->forceVisit($bookUrl . '/create-page')
->see('You do not have permission')->seePageIs('/');
- $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'create']);
- $this->visit($bookUrl . '/chapter/create')
+ $this->visit($bookUrl . '/create-chapter')
->type('test chapter', 'name')
->type('test description for chapter', 'description')
->press('Save Chapter')
->seePageIs($bookUrl . '/chapter/test-chapter');
- $this->visit($bookUrl . '/page/create')
+ $this->visit($bookUrl . '/create-page')
->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');
+ $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
+ ->seeInElement('.actions', 'New Chapter');
}
public function test_book_update_restriction()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookPage = $book->pages->first();
$bookChapter = $book->chapters->first();
public function test_book_delete_restriction()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookPage = $book->pages->first();
$bookChapter = $book->chapters->first();
public function test_chapter_view_restriction()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$chapterPage = $chapter->pages->first();
$chapterUrl = $chapter->getUrl();
public function test_chapter_create_restriction()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$chapterUrl = $chapter->getUrl();
$this->actingAs($this->user)
->visit($chapterUrl)
- ->seeInElement('.action-buttons', 'New Page');
+ ->seeInElement('.actions', 'New Page');
$this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
$this->forceVisit($chapterUrl . '/create-page')
->see('You do not have permission')->seePageIs('/');
- $this->visit($chapterUrl)->dontSeeInElement('.action-buttons', 'New Page');
+ $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page');
$this->setEntityRestrictions($chapter, ['view', 'create']);
->type('test content', 'html')
->press('Save Page')
->seePageIs($chapter->book->getUrl() . '/page/test-page');
- $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page');
+
+ $this->visit($chapterUrl)->seeInElement('.actions', 'New Page');
}
public function test_chapter_update_restriction()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$chapterPage = $chapter->pages->first();
$chapterUrl = $chapter->getUrl();
public function test_chapter_delete_restriction()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$chapterPage = $chapter->pages->first();
$chapterUrl = $chapter->getUrl();
public function test_page_view_restriction()
{
- $page = \BookStack\Page::first();
+ $page = Page::first();
$pageUrl = $page->getUrl();
$this->actingAs($this->user)
public function test_page_update_restriction()
{
- $page = \BookStack\Chapter::first();
+ $page = Chapter::first();
$pageUrl = $page->getUrl();
$this->actingAs($this->user)
public function test_page_delete_restriction()
{
- $page = \BookStack\Page::first();
+ $page = Page::first();
$pageUrl = $page->getUrl();
$this->actingAs($this->user)
->seePageIs($pageUrl . '/delete')->see('Delete Page');
}
+ public function test_bookshelf_restriction_form()
+ {
+ $shelf = Bookshelf::first();
+ $this->asAdmin()->visit($shelf->getUrl('/permissions'))
+ ->see('Bookshelf Permissions')
+ ->check('restricted')
+ ->check('restrictions[2][view]')
+ ->press('Save Permissions')
+ ->seeInDatabase('bookshelves', ['id' => $shelf->id, 'restricted' => true])
+ ->seeInDatabase('entity_permissions', [
+ 'restrictable_id' => $shelf->id,
+ 'restrictable_type' => Bookshelf::newModelInstance()->getMorphClass(),
+ 'role_id' => '2',
+ 'action' => 'view'
+ ]);
+ }
+
public function test_book_restriction_form()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$this->asAdmin()->visit($book->getUrl() . '/permissions')
->see('Book Permissions')
->check('restricted')
->check('restrictions[2][view]')
->press('Save Permissions')
->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
- ->seeInDatabase('restrictions', [
+ ->seeInDatabase('entity_permissions', [
'restrictable_id' => $book->id,
- 'restrictable_type' => 'BookStack\Book',
+ 'restrictable_type' => Book::newModelInstance()->getMorphClass(),
'role_id' => '2',
'action' => 'view'
]);
public function test_chapter_restriction_form()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$this->asAdmin()->visit($chapter->getUrl() . '/permissions')
->see('Chapter Permissions')
->check('restricted')
->check('restrictions[2][update]')
->press('Save Permissions')
->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
- ->seeInDatabase('restrictions', [
+ ->seeInDatabase('entity_permissions', [
'restrictable_id' => $chapter->id,
- 'restrictable_type' => 'BookStack\Chapter',
+ 'restrictable_type' => Chapter::newModelInstance()->getMorphClass(),
'role_id' => '2',
'action' => 'update'
]);
public function test_page_restriction_form()
{
- $page = \BookStack\Page::first();
+ $page = Page::first();
$this->asAdmin()->visit($page->getUrl() . '/permissions')
->see('Page Permissions')
->check('restricted')
->check('restrictions[2][delete]')
->press('Save Permissions')
->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
- ->seeInDatabase('restrictions', [
+ ->seeInDatabase('entity_permissions', [
'restrictable_id' => $page->id,
- 'restrictable_type' => 'BookStack\Page',
+ 'restrictable_type' => Page::newModelInstance()->getMorphClass(),
'role_id' => '2',
'action' => 'delete'
]);
public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$page = $chapter->pages->first();
$page2 = $chapter->pages[2];
public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$page = $chapter->pages->first();
$this->setEntityRestrictions($page, []);
public function test_restricted_pages_not_visible_on_chapter_pages()
{
- $chapter = \BookStack\Chapter::first();
+ $chapter = Chapter::first();
$page = $chapter->pages->first();
$this->setEntityRestrictions($page, []);
->dontSee($page->name);
}
+ public function test_bookshelf_update_restriction_override()
+ {
+ $shelf = Bookshelf::first();
+
+ $this->actingAs($this->viewer)
+ ->visit($shelf->getUrl('/edit'))
+ ->dontSee('Edit Book');
+
+ $this->setEntityRestrictions($shelf, ['view', 'delete']);
+
+ $this->forceVisit($shelf->getUrl('/edit'))
+ ->see('You do not have permission')->seePageIs('/');
+
+ $this->setEntityRestrictions($shelf, ['view', 'update']);
+
+ $this->visit($shelf->getUrl('/edit'))
+ ->seePageIs($shelf->getUrl('/edit'));
+ }
+
+ public function test_bookshelf_delete_restriction_override()
+ {
+ $shelf = Bookshelf::first();
+
+ $this->actingAs($this->viewer)
+ ->visit($shelf->getUrl('/delete'))
+ ->dontSee('Delete Book');
+
+ $this->setEntityRestrictions($shelf, ['view', 'update']);
+
+ $this->forceVisit($shelf->getUrl('/delete'))
+ ->see('You do not have permission')->seePageIs('/');
+
+ $this->setEntityRestrictions($shelf, ['view', 'delete']);
+
+ $this->visit($shelf->getUrl('/delete'))
+ ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
+ }
+
public function test_book_create_restriction_override()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookUrl = $book->getUrl();
$this->actingAs($this->viewer)
->visit($bookUrl)
- ->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ ->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'delete', 'update']);
- $this->forceVisit($bookUrl . '/chapter/create')
+ $this->forceVisit($bookUrl . '/create-chapter')
->see('You do not have permission')->seePageIs('/');
- $this->forceVisit($bookUrl . '/page/create')
+ $this->forceVisit($bookUrl . '/create-page')
->see('You do not have permission')->seePageIs('/');
- $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
- ->dontSeeInElement('.action-buttons', 'New Chapter');
+ $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
+ ->dontSeeInElement('.actions', 'New Chapter');
$this->setEntityRestrictions($book, ['view', 'create']);
- $this->visit($bookUrl . '/chapter/create')
+ $this->visit($bookUrl . '/create-chapter')
->type('test chapter', 'name')
->type('test description for chapter', 'description')
->press('Save Chapter')
->seePageIs($bookUrl . '/chapter/test-chapter');
- $this->visit($bookUrl . '/page/create')
+ $this->visit($bookUrl . '/create-page')
->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');
+ $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
+ ->seeInElement('.actions', 'New Chapter');
}
public function test_book_update_restriction_override()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookPage = $book->pages->first();
$bookChapter = $book->chapters->first();
public function test_book_delete_restriction_override()
{
- $book = \BookStack\Book::first();
+ $book = Book::first();
$bookPage = $book->pages->first();
$bookChapter = $book->chapters->first();
->see('Delete Chapter');
}
+ public function test_page_visible_if_has_permissions_when_book_not_visible()
+ {
+ $book = Book::first();
+
+ $this->setEntityRestrictions($book, []);
+
+ $bookChapter = $book->chapters->first();
+ $bookPage = $bookChapter->pages->first();
+ $this->setEntityRestrictions($bookPage, ['view']);
+
+ $this->actingAs($this->viewer);
+ $this->get($bookPage->getUrl());
+ $this->assertResponseOk();
+ $this->see($bookPage->name);
+ $this->dontSee(substr($book->name, 0, 15));
+ $this->dontSee(substr($bookChapter->name, 0, 15));
+ }
+
+ public function test_book_sort_view_permission()
+ {
+ $firstBook = Book::first();
+ $secondBook = Book::find(2);
+
+ $this->setEntityRestrictions($firstBook, ['view', 'update']);
+ $this->setEntityRestrictions($secondBook, ['view']);
+
+ // Test sort page visibility
+ $this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort')
+ ->see('You do not have permission')
+ ->seePageIs('/');
+
+ // Check sort page on first book
+ $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort');
+ }
+
+ public function test_book_sort_permission() {
+ $firstBook = Book::first();
+ $secondBook = Book::find(2);
+
+ $this->setEntityRestrictions($firstBook, ['view', 'update']);
+ $this->setEntityRestrictions($secondBook, ['view']);
+
+ $firstBookChapter = $this->newChapter(['name' => 'first book chapter'], $firstBook);
+ $secondBookChapter = $this->newChapter(['name' => 'second book chapter'], $secondBook);
+
+ // Create request data
+ $reqData = [
+ [
+ 'id' => $firstBookChapter->id,
+ 'sort' => 0,
+ 'parentChapter' => false,
+ 'type' => 'chapter',
+ 'book' => $secondBook->id
+ ]
+ ];
+
+ // Move chapter from first book to a second book
+ $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
+ ->followRedirects()
+ ->see('You do not have permission')
+ ->seePageIs('/');
+
+ $reqData = [
+ [
+ 'id' => $secondBookChapter->id,
+ 'sort' => 0,
+ 'parentChapter' => false,
+ 'type' => 'chapter',
+ 'book' => $firstBook->id
+ ]
+ ];
+
+ // Move chapter from second book to first book
+ $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
+ ->followRedirects()
+ ->see('You do not have permission')
+ ->seePageIs('/');
+ }
+
+ public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
+ {
+ $book = Book::first();
+ $this->setEntityRestrictions($book, []);
+ $bookChapter = $book->chapters->first();
+ $this->setEntityRestrictions($bookChapter, ['view']);
+
+ $this->actingAs($this->user)->visit($bookChapter->getUrl())
+ ->dontSee('New Page');
+
+ $this->setEntityRestrictions($bookChapter, ['view', 'create']);
+
+ $this->actingAs($this->user)->visit($bookChapter->getUrl())
+ ->click('New Page')
+ ->seeStatusCode(200)
+ ->type('test page', 'name')
+ ->type('test content', 'html')
+ ->press('Save Page')
+ ->seePageIs($book->getUrl('/page/test-page'))
+ ->seeStatusCode(200);
+ }
}