3 use BookStack\Entities\Book;
4 use BookStack\Entities\Bookshelf;
5 use BookStack\Entities\Chapter;
6 use BookStack\Entities\Entity;
7 use BookStack\Auth\User;
8 use BookStack\Entities\Repos\EntityRepo;
9 use BookStack\Entities\Page;
11 class RestrictionsTest extends BrowserKitTest
15 * @var \BookStack\Auth\User
24 public function setUp()
27 $this->user = $this->getEditor();
28 $this->viewer = $this->getViewer();
31 protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = [])
34 $this->user->roles->first(),
35 $this->viewer->roles->first(),
37 parent::setEntityRestrictions($entity, $actions, $roles);
40 public function test_bookshelf_view_restriction()
42 $shelf = Bookshelf::first();
44 $this->actingAs($this->user)
45 ->visit($shelf->getUrl())
46 ->seePageIs($shelf->getUrl());
48 $this->setEntityRestrictions($shelf, []);
50 $this->forceVisit($shelf->getUrl())
51 ->see('Bookshelf not found');
53 $this->setEntityRestrictions($shelf, ['view']);
55 $this->visit($shelf->getUrl())
59 public function test_bookshelf_update_restriction()
61 $shelf = BookShelf::first();
63 $this->actingAs($this->user)
64 ->visit($shelf->getUrl('/edit'))
67 $this->setEntityRestrictions($shelf, ['view', 'delete']);
69 $this->forceVisit($shelf->getUrl('/edit'))
70 ->see('You do not have permission')->seePageIs('/');
72 $this->setEntityRestrictions($shelf, ['view', 'update']);
74 $this->visit($shelf->getUrl('/edit'))
75 ->seePageIs($shelf->getUrl('/edit'));
78 public function test_bookshelf_delete_restriction()
80 $shelf = Book::first();
82 $this->actingAs($this->user)
83 ->visit($shelf->getUrl('/delete'))
86 $this->setEntityRestrictions($shelf, ['view', 'update']);
88 $this->forceVisit($shelf->getUrl('/delete'))
89 ->see('You do not have permission')->seePageIs('/');
91 $this->setEntityRestrictions($shelf, ['view', 'delete']);
93 $this->visit($shelf->getUrl('/delete'))
94 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
97 public function test_book_view_restriction()
99 $book = Book::first();
100 $bookPage = $book->pages->first();
101 $bookChapter = $book->chapters->first();
103 $bookUrl = $book->getUrl();
104 $this->actingAs($this->user)
106 ->seePageIs($bookUrl);
108 $this->setEntityRestrictions($book, []);
110 $this->forceVisit($bookUrl)
111 ->see('Book not found');
112 $this->forceVisit($bookPage->getUrl())
113 ->see('Page not found');
114 $this->forceVisit($bookChapter->getUrl())
115 ->see('Chapter not found');
117 $this->setEntityRestrictions($book, ['view']);
119 $this->visit($bookUrl)
121 $this->visit($bookPage->getUrl())
122 ->see($bookPage->name);
123 $this->visit($bookChapter->getUrl())
124 ->see($bookChapter->name);
127 public function test_book_create_restriction()
129 $book = Book::first();
131 $bookUrl = $book->getUrl();
132 $this->actingAs($this->viewer)
134 ->dontSeeInElement('.actions', 'New Page')
135 ->dontSeeInElement('.actions', 'New Chapter');
136 $this->actingAs($this->user)
138 ->seeInElement('.actions', 'New Page')
139 ->seeInElement('.actions', 'New Chapter');
141 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
143 $this->forceVisit($bookUrl . '/create-chapter')
144 ->see('You do not have permission')->seePageIs('/');
145 $this->forceVisit($bookUrl . '/create-page')
146 ->see('You do not have permission')->seePageIs('/');
147 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
148 ->dontSeeInElement('.actions', 'New Chapter');
150 $this->setEntityRestrictions($book, ['view', 'create']);
152 $this->visit($bookUrl . '/create-chapter')
153 ->type('test chapter', 'name')
154 ->type('test description for chapter', 'description')
155 ->press('Save Chapter')
156 ->seePageIs($bookUrl . '/chapter/test-chapter');
157 $this->visit($bookUrl . '/create-page')
158 ->type('test page', 'name')
159 ->type('test content', 'html')
161 ->seePageIs($bookUrl . '/page/test-page');
162 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
163 ->seeInElement('.actions', 'New Chapter');
166 public function test_book_update_restriction()
168 $book = Book::first();
169 $bookPage = $book->pages->first();
170 $bookChapter = $book->chapters->first();
172 $bookUrl = $book->getUrl();
173 $this->actingAs($this->user)
174 ->visit($bookUrl . '/edit')
177 $this->setEntityRestrictions($book, ['view', 'delete']);
179 $this->forceVisit($bookUrl . '/edit')
180 ->see('You do not have permission')->seePageIs('/');
181 $this->forceVisit($bookPage->getUrl() . '/edit')
182 ->see('You do not have permission')->seePageIs('/');
183 $this->forceVisit($bookChapter->getUrl() . '/edit')
184 ->see('You do not have permission')->seePageIs('/');
186 $this->setEntityRestrictions($book, ['view', 'update']);
188 $this->visit($bookUrl . '/edit')
189 ->seePageIs($bookUrl . '/edit');
190 $this->visit($bookPage->getUrl() . '/edit')
191 ->seePageIs($bookPage->getUrl() . '/edit');
192 $this->visit($bookChapter->getUrl() . '/edit')
193 ->see('Edit Chapter');
196 public function test_book_delete_restriction()
198 $book = Book::first();
199 $bookPage = $book->pages->first();
200 $bookChapter = $book->chapters->first();
202 $bookUrl = $book->getUrl();
203 $this->actingAs($this->user)
204 ->visit($bookUrl . '/delete')
205 ->see('Delete Book');
207 $this->setEntityRestrictions($book, ['view', 'update']);
209 $this->forceVisit($bookUrl . '/delete')
210 ->see('You do not have permission')->seePageIs('/');
211 $this->forceVisit($bookPage->getUrl() . '/delete')
212 ->see('You do not have permission')->seePageIs('/');
213 $this->forceVisit($bookChapter->getUrl() . '/delete')
214 ->see('You do not have permission')->seePageIs('/');
216 $this->setEntityRestrictions($book, ['view', 'delete']);
218 $this->visit($bookUrl . '/delete')
219 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
220 $this->visit($bookPage->getUrl() . '/delete')
221 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
222 $this->visit($bookChapter->getUrl() . '/delete')
223 ->see('Delete Chapter');
226 public function test_chapter_view_restriction()
228 $chapter = Chapter::first();
229 $chapterPage = $chapter->pages->first();
231 $chapterUrl = $chapter->getUrl();
232 $this->actingAs($this->user)
234 ->seePageIs($chapterUrl);
236 $this->setEntityRestrictions($chapter, []);
238 $this->forceVisit($chapterUrl)
239 ->see('Chapter not found');
240 $this->forceVisit($chapterPage->getUrl())
241 ->see('Page not found');
243 $this->setEntityRestrictions($chapter, ['view']);
245 $this->visit($chapterUrl)
246 ->see($chapter->name);
247 $this->visit($chapterPage->getUrl())
248 ->see($chapterPage->name);
251 public function test_chapter_create_restriction()
253 $chapter = Chapter::first();
255 $chapterUrl = $chapter->getUrl();
256 $this->actingAs($this->user)
258 ->seeInElement('.actions', 'New Page');
260 $this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
262 $this->forceVisit($chapterUrl . '/create-page')
263 ->see('You do not have permission')->seePageIs('/');
264 $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page');
266 $this->setEntityRestrictions($chapter, ['view', 'create']);
269 $this->visit($chapterUrl . '/create-page')
270 ->type('test page', 'name')
271 ->type('test content', 'html')
273 ->seePageIs($chapter->book->getUrl() . '/page/test-page');
275 $this->visit($chapterUrl)->seeInElement('.actions', 'New Page');
278 public function test_chapter_update_restriction()
280 $chapter = Chapter::first();
281 $chapterPage = $chapter->pages->first();
283 $chapterUrl = $chapter->getUrl();
284 $this->actingAs($this->user)
285 ->visit($chapterUrl . '/edit')
286 ->see('Edit Chapter');
288 $this->setEntityRestrictions($chapter, ['view', 'delete']);
290 $this->forceVisit($chapterUrl . '/edit')
291 ->see('You do not have permission')->seePageIs('/');
292 $this->forceVisit($chapterPage->getUrl() . '/edit')
293 ->see('You do not have permission')->seePageIs('/');
295 $this->setEntityRestrictions($chapter, ['view', 'update']);
297 $this->visit($chapterUrl . '/edit')
298 ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter');
299 $this->visit($chapterPage->getUrl() . '/edit')
300 ->seePageIs($chapterPage->getUrl() . '/edit');
303 public function test_chapter_delete_restriction()
305 $chapter = Chapter::first();
306 $chapterPage = $chapter->pages->first();
308 $chapterUrl = $chapter->getUrl();
309 $this->actingAs($this->user)
310 ->visit($chapterUrl . '/delete')
311 ->see('Delete Chapter');
313 $this->setEntityRestrictions($chapter, ['view', 'update']);
315 $this->forceVisit($chapterUrl . '/delete')
316 ->see('You do not have permission')->seePageIs('/');
317 $this->forceVisit($chapterPage->getUrl() . '/delete')
318 ->see('You do not have permission')->seePageIs('/');
320 $this->setEntityRestrictions($chapter, ['view', 'delete']);
322 $this->visit($chapterUrl . '/delete')
323 ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter');
324 $this->visit($chapterPage->getUrl() . '/delete')
325 ->seePageIs($chapterPage->getUrl() . '/delete')->see('Delete Page');
328 public function test_page_view_restriction()
330 $page = \BookStack\Entities\Page::first();
332 $pageUrl = $page->getUrl();
333 $this->actingAs($this->user)
335 ->seePageIs($pageUrl);
337 $this->setEntityRestrictions($page, ['update', 'delete']);
339 $this->forceVisit($pageUrl)
340 ->see('Page not found');
342 $this->setEntityRestrictions($page, ['view']);
344 $this->visit($pageUrl)
348 public function test_page_update_restriction()
350 $page = Chapter::first();
352 $pageUrl = $page->getUrl();
353 $this->actingAs($this->user)
354 ->visit($pageUrl . '/edit')
355 ->seeInField('name', $page->name);
357 $this->setEntityRestrictions($page, ['view', 'delete']);
359 $this->forceVisit($pageUrl . '/edit')
360 ->see('You do not have permission')->seePageIs('/');
362 $this->setEntityRestrictions($page, ['view', 'update']);
364 $this->visit($pageUrl . '/edit')
365 ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name);
368 public function test_page_delete_restriction()
370 $page = \BookStack\Entities\Page::first();
372 $pageUrl = $page->getUrl();
373 $this->actingAs($this->user)
374 ->visit($pageUrl . '/delete')
375 ->see('Delete Page');
377 $this->setEntityRestrictions($page, ['view', 'update']);
379 $this->forceVisit($pageUrl . '/delete')
380 ->see('You do not have permission')->seePageIs('/');
382 $this->setEntityRestrictions($page, ['view', 'delete']);
384 $this->visit($pageUrl . '/delete')
385 ->seePageIs($pageUrl . '/delete')->see('Delete Page');
388 public function test_bookshelf_restriction_form()
390 $shelf = Bookshelf::first();
391 $this->asAdmin()->visit($shelf->getUrl('/permissions'))
392 ->see('Bookshelf Permissions')
393 ->check('restricted')
394 ->check('restrictions[2][view]')
395 ->press('Save Permissions')
396 ->seeInDatabase('bookshelves', ['id' => $shelf->id, 'restricted' => true])
397 ->seeInDatabase('entity_permissions', [
398 'restrictable_id' => $shelf->id,
399 'restrictable_type' => Bookshelf::newModelInstance()->getMorphClass(),
405 public function test_book_restriction_form()
407 $book = Book::first();
408 $this->asAdmin()->visit($book->getUrl() . '/permissions')
409 ->see('Book Permissions')
410 ->check('restricted')
411 ->check('restrictions[2][view]')
412 ->press('Save Permissions')
413 ->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
414 ->seeInDatabase('entity_permissions', [
415 'restrictable_id' => $book->id,
416 'restrictable_type' => Book::newModelInstance()->getMorphClass(),
422 public function test_chapter_restriction_form()
424 $chapter = Chapter::first();
425 $this->asAdmin()->visit($chapter->getUrl() . '/permissions')
426 ->see('Chapter Permissions')
427 ->check('restricted')
428 ->check('restrictions[2][update]')
429 ->press('Save Permissions')
430 ->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
431 ->seeInDatabase('entity_permissions', [
432 'restrictable_id' => $chapter->id,
433 'restrictable_type' => Chapter::newModelInstance()->getMorphClass(),
439 public function test_page_restriction_form()
441 $page = \BookStack\Entities\Page::first();
442 $this->asAdmin()->visit($page->getUrl() . '/permissions')
443 ->see('Page Permissions')
444 ->check('restricted')
445 ->check('restrictions[2][delete]')
446 ->press('Save Permissions')
447 ->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
448 ->seeInDatabase('entity_permissions', [
449 'restrictable_id' => $page->id,
450 'restrictable_type' => Page::newModelInstance()->getMorphClass(),
456 public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
458 $chapter = Chapter::first();
459 $page = $chapter->pages->first();
460 $page2 = $chapter->pages[2];
462 $this->setEntityRestrictions($page, []);
464 $this->actingAs($this->user)
465 ->visit($page2->getUrl())
466 ->dontSeeInElement('.sidebar-page-list', $page->name);
469 public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
471 $chapter = Chapter::first();
472 $page = $chapter->pages->first();
474 $this->setEntityRestrictions($page, []);
476 $this->actingAs($this->user)
477 ->visit($chapter->getUrl())
478 ->dontSeeInElement('.sidebar-page-list', $page->name);
481 public function test_restricted_pages_not_visible_on_chapter_pages()
483 $chapter = Chapter::first();
484 $page = $chapter->pages->first();
486 $this->setEntityRestrictions($page, []);
488 $this->actingAs($this->user)
489 ->visit($chapter->getUrl())
490 ->dontSee($page->name);
493 public function test_bookshelf_update_restriction_override()
495 $shelf = Bookshelf::first();
497 $this->actingAs($this->viewer)
498 ->visit($shelf->getUrl('/edit'))
499 ->dontSee('Edit Book');
501 $this->setEntityRestrictions($shelf, ['view', 'delete']);
503 $this->forceVisit($shelf->getUrl('/edit'))
504 ->see('You do not have permission')->seePageIs('/');
506 $this->setEntityRestrictions($shelf, ['view', 'update']);
508 $this->visit($shelf->getUrl('/edit'))
509 ->seePageIs($shelf->getUrl('/edit'));
512 public function test_bookshelf_delete_restriction_override()
514 $shelf = Bookshelf::first();
516 $this->actingAs($this->viewer)
517 ->visit($shelf->getUrl('/delete'))
518 ->dontSee('Delete Book');
520 $this->setEntityRestrictions($shelf, ['view', 'update']);
522 $this->forceVisit($shelf->getUrl('/delete'))
523 ->see('You do not have permission')->seePageIs('/');
525 $this->setEntityRestrictions($shelf, ['view', 'delete']);
527 $this->visit($shelf->getUrl('/delete'))
528 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
531 public function test_book_create_restriction_override()
533 $book = Book::first();
535 $bookUrl = $book->getUrl();
536 $this->actingAs($this->viewer)
538 ->dontSeeInElement('.actions', 'New Page')
539 ->dontSeeInElement('.actions', 'New Chapter');
541 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
543 $this->forceVisit($bookUrl . '/create-chapter')
544 ->see('You do not have permission')->seePageIs('/');
545 $this->forceVisit($bookUrl . '/create-page')
546 ->see('You do not have permission')->seePageIs('/');
547 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
548 ->dontSeeInElement('.actions', 'New Chapter');
550 $this->setEntityRestrictions($book, ['view', 'create']);
552 $this->visit($bookUrl . '/create-chapter')
553 ->type('test chapter', 'name')
554 ->type('test description for chapter', 'description')
555 ->press('Save Chapter')
556 ->seePageIs($bookUrl . '/chapter/test-chapter');
557 $this->visit($bookUrl . '/create-page')
558 ->type('test page', 'name')
559 ->type('test content', 'html')
561 ->seePageIs($bookUrl . '/page/test-page');
562 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
563 ->seeInElement('.actions', 'New Chapter');
566 public function test_book_update_restriction_override()
568 $book = Book::first();
569 $bookPage = $book->pages->first();
570 $bookChapter = $book->chapters->first();
572 $bookUrl = $book->getUrl();
573 $this->actingAs($this->viewer)
574 ->visit($bookUrl . '/edit')
575 ->dontSee('Edit Book');
577 $this->setEntityRestrictions($book, ['view', 'delete']);
579 $this->forceVisit($bookUrl . '/edit')
580 ->see('You do not have permission')->seePageIs('/');
581 $this->forceVisit($bookPage->getUrl() . '/edit')
582 ->see('You do not have permission')->seePageIs('/');
583 $this->forceVisit($bookChapter->getUrl() . '/edit')
584 ->see('You do not have permission')->seePageIs('/');
586 $this->setEntityRestrictions($book, ['view', 'update']);
588 $this->visit($bookUrl . '/edit')
589 ->seePageIs($bookUrl . '/edit');
590 $this->visit($bookPage->getUrl() . '/edit')
591 ->seePageIs($bookPage->getUrl() . '/edit');
592 $this->visit($bookChapter->getUrl() . '/edit')
593 ->see('Edit Chapter');
596 public function test_book_delete_restriction_override()
598 $book = Book::first();
599 $bookPage = $book->pages->first();
600 $bookChapter = $book->chapters->first();
602 $bookUrl = $book->getUrl();
603 $this->actingAs($this->viewer)
604 ->visit($bookUrl . '/delete')
605 ->dontSee('Delete Book');
607 $this->setEntityRestrictions($book, ['view', 'update']);
609 $this->forceVisit($bookUrl . '/delete')
610 ->see('You do not have permission')->seePageIs('/');
611 $this->forceVisit($bookPage->getUrl() . '/delete')
612 ->see('You do not have permission')->seePageIs('/');
613 $this->forceVisit($bookChapter->getUrl() . '/delete')
614 ->see('You do not have permission')->seePageIs('/');
616 $this->setEntityRestrictions($book, ['view', 'delete']);
618 $this->visit($bookUrl . '/delete')
619 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
620 $this->visit($bookPage->getUrl() . '/delete')
621 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
622 $this->visit($bookChapter->getUrl() . '/delete')
623 ->see('Delete Chapter');
626 public function test_page_visible_if_has_permissions_when_book_not_visible()
628 $book = Book::first();
630 $this->setEntityRestrictions($book, []);
632 $bookChapter = $book->chapters->first();
633 $bookPage = $bookChapter->pages->first();
634 $this->setEntityRestrictions($bookPage, ['view']);
636 $this->actingAs($this->viewer);
637 $this->get($bookPage->getUrl());
638 $this->assertResponseOk();
639 $this->see($bookPage->name);
640 $this->dontSee(substr($book->name, 0, 15));
641 $this->dontSee(substr($bookChapter->name, 0, 15));
644 public function test_book_sort_view_permission()
646 $firstBook = Book::first();
647 $secondBook = Book::find(2);
649 $this->setEntityRestrictions($firstBook, ['view', 'update']);
650 $this->setEntityRestrictions($secondBook, ['view']);
652 // Test sort page visibility
653 $this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort')
654 ->see('You do not have permission')
657 // Check sort page on first book
658 $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort');
661 public function test_book_sort_permission() {
662 $firstBook = Book::first();
663 $secondBook = Book::find(2);
665 $this->setEntityRestrictions($firstBook, ['view', 'update']);
666 $this->setEntityRestrictions($secondBook, ['view']);
668 $firstBookChapter = $this->app[EntityRepo::class]->createFromInput('chapter',
669 ['name' => 'first book chapter'], $firstBook);
670 $secondBookChapter = $this->app[EntityRepo::class]->createFromInput('chapter',
671 ['name' => 'second book chapter'], $secondBook);
673 // Create request data
676 'id' => $firstBookChapter->id,
678 'parentChapter' => false,
680 'book' => $secondBook->id
684 // Move chapter from first book to a second book
685 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
687 ->see('You do not have permission')
692 'id' => $secondBookChapter->id,
694 'parentChapter' => false,
696 'book' => $firstBook->id
700 // Move chapter from second book to first book
701 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
703 ->see('You do not have permission')
707 public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
709 $book = Book::first();
710 $this->setEntityRestrictions($book, []);
711 $bookChapter = $book->chapters->first();
712 $this->setEntityRestrictions($bookChapter, ['view']);
714 $this->actingAs($this->user)->visit($bookChapter->getUrl())
715 ->dontSee('New Page');
717 $this->setEntityRestrictions($bookChapter, ['view', 'create']);
719 $this->actingAs($this->user)->visit($bookChapter->getUrl())
722 ->type('test page', 'name')
723 ->type('test content', 'html')
725 ->seePageIs($book->getUrl('/page/test-page'))
726 ->seeStatusCode(200);