4 use BookStack\Bookshelf;
7 use BookStack\Repos\EntityRepo;
9 class RestrictionsTest extends BrowserKitTest
22 public function setUp()
25 $this->user = $this->getEditor();
26 $this->viewer = $this->getViewer();
29 protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = [])
32 $this->user->roles->first(),
33 $this->viewer->roles->first(),
35 parent::setEntityRestrictions($entity, $actions, $roles);
38 public function test_bookshelf_view_restriction()
40 $shelf = Bookshelf::first();
42 $this->actingAs($this->user)
43 ->visit($shelf->getUrl())
44 ->seePageIs($shelf->getUrl());
46 $this->setEntityRestrictions($shelf, []);
48 $this->forceVisit($shelf->getUrl())
49 ->see('Bookshelf not found');
51 $this->setEntityRestrictions($shelf, ['view']);
53 $this->visit($shelf->getUrl())
57 public function test_bookshelf_update_restriction()
59 $shelf = BookShelf::first();
61 $this->actingAs($this->user)
62 ->visit($shelf->getUrl('/edit'))
65 $this->setEntityRestrictions($shelf, ['view', 'delete']);
67 $this->forceVisit($shelf->getUrl('/edit'))
68 ->see('You do not have permission')->seePageIs('/');
70 $this->setEntityRestrictions($shelf, ['view', 'update']);
72 $this->visit($shelf->getUrl('/edit'))
73 ->seePageIs($shelf->getUrl('/edit'));
76 public function test_bookshelf_delete_restriction()
78 $shelf = Book::first();
80 $this->actingAs($this->user)
81 ->visit($shelf->getUrl('/delete'))
84 $this->setEntityRestrictions($shelf, ['view', 'update']);
86 $this->forceVisit($shelf->getUrl('/delete'))
87 ->see('You do not have permission')->seePageIs('/');
89 $this->setEntityRestrictions($shelf, ['view', 'delete']);
91 $this->visit($shelf->getUrl('/delete'))
92 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
95 public function test_book_view_restriction()
97 $book = Book::first();
98 $bookPage = $book->pages->first();
99 $bookChapter = $book->chapters->first();
101 $bookUrl = $book->getUrl();
102 $this->actingAs($this->user)
104 ->seePageIs($bookUrl);
106 $this->setEntityRestrictions($book, []);
108 $this->forceVisit($bookUrl)
109 ->see('Book not found');
110 $this->forceVisit($bookPage->getUrl())
111 ->see('Page not found');
112 $this->forceVisit($bookChapter->getUrl())
113 ->see('Chapter not found');
115 $this->setEntityRestrictions($book, ['view']);
117 $this->visit($bookUrl)
119 $this->visit($bookPage->getUrl())
120 ->see($bookPage->name);
121 $this->visit($bookChapter->getUrl())
122 ->see($bookChapter->name);
125 public function test_book_create_restriction()
127 $book = Book::first();
129 $bookUrl = $book->getUrl();
130 $this->actingAs($this->viewer)
132 ->dontSeeInElement('.action-buttons', 'New Page')
133 ->dontSeeInElement('.action-buttons', 'New Chapter');
134 $this->actingAs($this->user)
136 ->seeInElement('.action-buttons', 'New Page')
137 ->seeInElement('.action-buttons', 'New Chapter');
139 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
141 $this->forceVisit($bookUrl . '/create-chapter')
142 ->see('You do not have permission')->seePageIs('/');
143 $this->forceVisit($bookUrl . '/create-page')
144 ->see('You do not have permission')->seePageIs('/');
145 $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
146 ->dontSeeInElement('.action-buttons', 'New Chapter');
148 $this->setEntityRestrictions($book, ['view', 'create']);
150 $this->visit($bookUrl . '/create-chapter')
151 ->type('test chapter', 'name')
152 ->type('test description for chapter', 'description')
153 ->press('Save Chapter')
154 ->seePageIs($bookUrl . '/chapter/test-chapter');
155 $this->visit($bookUrl . '/create-page')
156 ->type('test page', 'name')
157 ->type('test content', 'html')
159 ->seePageIs($bookUrl . '/page/test-page');
160 $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
161 ->seeInElement('.action-buttons', 'New Chapter');
164 public function test_book_update_restriction()
166 $book = Book::first();
167 $bookPage = $book->pages->first();
168 $bookChapter = $book->chapters->first();
170 $bookUrl = $book->getUrl();
171 $this->actingAs($this->user)
172 ->visit($bookUrl . '/edit')
175 $this->setEntityRestrictions($book, ['view', 'delete']);
177 $this->forceVisit($bookUrl . '/edit')
178 ->see('You do not have permission')->seePageIs('/');
179 $this->forceVisit($bookPage->getUrl() . '/edit')
180 ->see('You do not have permission')->seePageIs('/');
181 $this->forceVisit($bookChapter->getUrl() . '/edit')
182 ->see('You do not have permission')->seePageIs('/');
184 $this->setEntityRestrictions($book, ['view', 'update']);
186 $this->visit($bookUrl . '/edit')
187 ->seePageIs($bookUrl . '/edit');
188 $this->visit($bookPage->getUrl() . '/edit')
189 ->seePageIs($bookPage->getUrl() . '/edit');
190 $this->visit($bookChapter->getUrl() . '/edit')
191 ->see('Edit Chapter');
194 public function test_book_delete_restriction()
196 $book = Book::first();
197 $bookPage = $book->pages->first();
198 $bookChapter = $book->chapters->first();
200 $bookUrl = $book->getUrl();
201 $this->actingAs($this->user)
202 ->visit($bookUrl . '/delete')
203 ->see('Delete Book');
205 $this->setEntityRestrictions($book, ['view', 'update']);
207 $this->forceVisit($bookUrl . '/delete')
208 ->see('You do not have permission')->seePageIs('/');
209 $this->forceVisit($bookPage->getUrl() . '/delete')
210 ->see('You do not have permission')->seePageIs('/');
211 $this->forceVisit($bookChapter->getUrl() . '/delete')
212 ->see('You do not have permission')->seePageIs('/');
214 $this->setEntityRestrictions($book, ['view', 'delete']);
216 $this->visit($bookUrl . '/delete')
217 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
218 $this->visit($bookPage->getUrl() . '/delete')
219 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
220 $this->visit($bookChapter->getUrl() . '/delete')
221 ->see('Delete Chapter');
224 public function test_chapter_view_restriction()
226 $chapter = \BookStack\Chapter::first();
227 $chapterPage = $chapter->pages->first();
229 $chapterUrl = $chapter->getUrl();
230 $this->actingAs($this->user)
232 ->seePageIs($chapterUrl);
234 $this->setEntityRestrictions($chapter, []);
236 $this->forceVisit($chapterUrl)
237 ->see('Chapter not found');
238 $this->forceVisit($chapterPage->getUrl())
239 ->see('Page not found');
241 $this->setEntityRestrictions($chapter, ['view']);
243 $this->visit($chapterUrl)
244 ->see($chapter->name);
245 $this->visit($chapterPage->getUrl())
246 ->see($chapterPage->name);
249 public function test_chapter_create_restriction()
251 $chapter = \BookStack\Chapter::first();
253 $chapterUrl = $chapter->getUrl();
254 $this->actingAs($this->user)
256 ->seeInElement('.action-buttons', 'New Page');
258 $this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
260 $this->forceVisit($chapterUrl . '/create-page')
261 ->see('You do not have permission')->seePageIs('/');
262 $this->visit($chapterUrl)->dontSeeInElement('.action-buttons', 'New Page');
264 $this->setEntityRestrictions($chapter, ['view', 'create']);
267 $this->visit($chapterUrl . '/create-page')
268 ->type('test page', 'name')
269 ->type('test content', 'html')
271 ->seePageIs($chapter->book->getUrl() . '/page/test-page');
273 $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page');
276 public function test_chapter_update_restriction()
278 $chapter = \BookStack\Chapter::first();
279 $chapterPage = $chapter->pages->first();
281 $chapterUrl = $chapter->getUrl();
282 $this->actingAs($this->user)
283 ->visit($chapterUrl . '/edit')
284 ->see('Edit Chapter');
286 $this->setEntityRestrictions($chapter, ['view', 'delete']);
288 $this->forceVisit($chapterUrl . '/edit')
289 ->see('You do not have permission')->seePageIs('/');
290 $this->forceVisit($chapterPage->getUrl() . '/edit')
291 ->see('You do not have permission')->seePageIs('/');
293 $this->setEntityRestrictions($chapter, ['view', 'update']);
295 $this->visit($chapterUrl . '/edit')
296 ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter');
297 $this->visit($chapterPage->getUrl() . '/edit')
298 ->seePageIs($chapterPage->getUrl() . '/edit');
301 public function test_chapter_delete_restriction()
303 $chapter = \BookStack\Chapter::first();
304 $chapterPage = $chapter->pages->first();
306 $chapterUrl = $chapter->getUrl();
307 $this->actingAs($this->user)
308 ->visit($chapterUrl . '/delete')
309 ->see('Delete Chapter');
311 $this->setEntityRestrictions($chapter, ['view', 'update']);
313 $this->forceVisit($chapterUrl . '/delete')
314 ->see('You do not have permission')->seePageIs('/');
315 $this->forceVisit($chapterPage->getUrl() . '/delete')
316 ->see('You do not have permission')->seePageIs('/');
318 $this->setEntityRestrictions($chapter, ['view', 'delete']);
320 $this->visit($chapterUrl . '/delete')
321 ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter');
322 $this->visit($chapterPage->getUrl() . '/delete')
323 ->seePageIs($chapterPage->getUrl() . '/delete')->see('Delete Page');
326 public function test_page_view_restriction()
328 $page = \BookStack\Page::first();
330 $pageUrl = $page->getUrl();
331 $this->actingAs($this->user)
333 ->seePageIs($pageUrl);
335 $this->setEntityRestrictions($page, ['update', 'delete']);
337 $this->forceVisit($pageUrl)
338 ->see('Page not found');
340 $this->setEntityRestrictions($page, ['view']);
342 $this->visit($pageUrl)
346 public function test_page_update_restriction()
348 $page = \BookStack\Chapter::first();
350 $pageUrl = $page->getUrl();
351 $this->actingAs($this->user)
352 ->visit($pageUrl . '/edit')
353 ->seeInField('name', $page->name);
355 $this->setEntityRestrictions($page, ['view', 'delete']);
357 $this->forceVisit($pageUrl . '/edit')
358 ->see('You do not have permission')->seePageIs('/');
360 $this->setEntityRestrictions($page, ['view', 'update']);
362 $this->visit($pageUrl . '/edit')
363 ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name);
366 public function test_page_delete_restriction()
368 $page = \BookStack\Page::first();
370 $pageUrl = $page->getUrl();
371 $this->actingAs($this->user)
372 ->visit($pageUrl . '/delete')
373 ->see('Delete Page');
375 $this->setEntityRestrictions($page, ['view', 'update']);
377 $this->forceVisit($pageUrl . '/delete')
378 ->see('You do not have permission')->seePageIs('/');
380 $this->setEntityRestrictions($page, ['view', 'delete']);
382 $this->visit($pageUrl . '/delete')
383 ->seePageIs($pageUrl . '/delete')->see('Delete Page');
386 public function test_bookshelf_restriction_form()
388 $shelf = Bookshelf::first();
389 $this->asAdmin()->visit($shelf->getUrl('/permissions'))
390 ->see('Bookshelf Permissions')
391 ->check('restricted')
392 ->check('restrictions[2][view]')
393 ->press('Save Permissions')
394 ->seeInDatabase('bookshelves', ['id' => $shelf->id, 'restricted' => true])
395 ->seeInDatabase('entity_permissions', [
396 'restrictable_id' => $shelf->id,
397 'restrictable_type' => 'BookStack\Bookshelf',
403 public function test_book_restriction_form()
405 $book = Book::first();
406 $this->asAdmin()->visit($book->getUrl() . '/permissions')
407 ->see('Book Permissions')
408 ->check('restricted')
409 ->check('restrictions[2][view]')
410 ->press('Save Permissions')
411 ->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
412 ->seeInDatabase('entity_permissions', [
413 'restrictable_id' => $book->id,
414 'restrictable_type' => 'BookStack\Book',
420 public function test_chapter_restriction_form()
422 $chapter = \BookStack\Chapter::first();
423 $this->asAdmin()->visit($chapter->getUrl() . '/permissions')
424 ->see('Chapter Permissions')
425 ->check('restricted')
426 ->check('restrictions[2][update]')
427 ->press('Save Permissions')
428 ->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
429 ->seeInDatabase('entity_permissions', [
430 'restrictable_id' => $chapter->id,
431 'restrictable_type' => 'BookStack\Chapter',
437 public function test_page_restriction_form()
439 $page = \BookStack\Page::first();
440 $this->asAdmin()->visit($page->getUrl() . '/permissions')
441 ->see('Page Permissions')
442 ->check('restricted')
443 ->check('restrictions[2][delete]')
444 ->press('Save Permissions')
445 ->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
446 ->seeInDatabase('entity_permissions', [
447 'restrictable_id' => $page->id,
448 'restrictable_type' => 'BookStack\Page',
454 public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
456 $chapter = \BookStack\Chapter::first();
457 $page = $chapter->pages->first();
458 $page2 = $chapter->pages[2];
460 $this->setEntityRestrictions($page, []);
462 $this->actingAs($this->user)
463 ->visit($page2->getUrl())
464 ->dontSeeInElement('.sidebar-page-list', $page->name);
467 public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
469 $chapter = \BookStack\Chapter::first();
470 $page = $chapter->pages->first();
472 $this->setEntityRestrictions($page, []);
474 $this->actingAs($this->user)
475 ->visit($chapter->getUrl())
476 ->dontSeeInElement('.sidebar-page-list', $page->name);
479 public function test_restricted_pages_not_visible_on_chapter_pages()
481 $chapter = \BookStack\Chapter::first();
482 $page = $chapter->pages->first();
484 $this->setEntityRestrictions($page, []);
486 $this->actingAs($this->user)
487 ->visit($chapter->getUrl())
488 ->dontSee($page->name);
491 public function test_bookshelf_update_restriction_override()
493 $shelf = Bookshelf::first();
495 $this->actingAs($this->viewer)
496 ->visit($shelf->getUrl('/edit'))
497 ->dontSee('Edit Book');
499 $this->setEntityRestrictions($shelf, ['view', 'delete']);
501 $this->forceVisit($shelf->getUrl('/edit'))
502 ->see('You do not have permission')->seePageIs('/');
504 $this->setEntityRestrictions($shelf, ['view', 'update']);
506 $this->visit($shelf->getUrl('/edit'))
507 ->seePageIs($shelf->getUrl('/edit'));
510 public function test_bookshelf_delete_restriction_override()
512 $shelf = Bookshelf::first();
514 $this->actingAs($this->viewer)
515 ->visit($shelf->getUrl('/delete'))
516 ->dontSee('Delete Book');
518 $this->setEntityRestrictions($shelf, ['view', 'update']);
520 $this->forceVisit($shelf->getUrl('/delete'))
521 ->see('You do not have permission')->seePageIs('/');
523 $this->setEntityRestrictions($shelf, ['view', 'delete']);
525 $this->visit($shelf->getUrl('/delete'))
526 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
529 public function test_book_create_restriction_override()
531 $book = Book::first();
533 $bookUrl = $book->getUrl();
534 $this->actingAs($this->viewer)
536 ->dontSeeInElement('.action-buttons', 'New Page')
537 ->dontSeeInElement('.action-buttons', 'New Chapter');
539 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
541 $this->forceVisit($bookUrl . '/create-chapter')
542 ->see('You do not have permission')->seePageIs('/');
543 $this->forceVisit($bookUrl . '/create-page')
544 ->see('You do not have permission')->seePageIs('/');
545 $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
546 ->dontSeeInElement('.action-buttons', 'New Chapter');
548 $this->setEntityRestrictions($book, ['view', 'create']);
550 $this->visit($bookUrl . '/create-chapter')
551 ->type('test chapter', 'name')
552 ->type('test description for chapter', 'description')
553 ->press('Save Chapter')
554 ->seePageIs($bookUrl . '/chapter/test-chapter');
555 $this->visit($bookUrl . '/create-page')
556 ->type('test page', 'name')
557 ->type('test content', 'html')
559 ->seePageIs($bookUrl . '/page/test-page');
560 $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
561 ->seeInElement('.action-buttons', 'New Chapter');
564 public function test_book_update_restriction_override()
566 $book = Book::first();
567 $bookPage = $book->pages->first();
568 $bookChapter = $book->chapters->first();
570 $bookUrl = $book->getUrl();
571 $this->actingAs($this->viewer)
572 ->visit($bookUrl . '/edit')
573 ->dontSee('Edit Book');
575 $this->setEntityRestrictions($book, ['view', 'delete']);
577 $this->forceVisit($bookUrl . '/edit')
578 ->see('You do not have permission')->seePageIs('/');
579 $this->forceVisit($bookPage->getUrl() . '/edit')
580 ->see('You do not have permission')->seePageIs('/');
581 $this->forceVisit($bookChapter->getUrl() . '/edit')
582 ->see('You do not have permission')->seePageIs('/');
584 $this->setEntityRestrictions($book, ['view', 'update']);
586 $this->visit($bookUrl . '/edit')
587 ->seePageIs($bookUrl . '/edit');
588 $this->visit($bookPage->getUrl() . '/edit')
589 ->seePageIs($bookPage->getUrl() . '/edit');
590 $this->visit($bookChapter->getUrl() . '/edit')
591 ->see('Edit Chapter');
594 public function test_book_delete_restriction_override()
596 $book = Book::first();
597 $bookPage = $book->pages->first();
598 $bookChapter = $book->chapters->first();
600 $bookUrl = $book->getUrl();
601 $this->actingAs($this->viewer)
602 ->visit($bookUrl . '/delete')
603 ->dontSee('Delete Book');
605 $this->setEntityRestrictions($book, ['view', 'update']);
607 $this->forceVisit($bookUrl . '/delete')
608 ->see('You do not have permission')->seePageIs('/');
609 $this->forceVisit($bookPage->getUrl() . '/delete')
610 ->see('You do not have permission')->seePageIs('/');
611 $this->forceVisit($bookChapter->getUrl() . '/delete')
612 ->see('You do not have permission')->seePageIs('/');
614 $this->setEntityRestrictions($book, ['view', 'delete']);
616 $this->visit($bookUrl . '/delete')
617 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
618 $this->visit($bookPage->getUrl() . '/delete')
619 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
620 $this->visit($bookChapter->getUrl() . '/delete')
621 ->see('Delete Chapter');
624 public function test_page_visible_if_has_permissions_when_book_not_visible()
626 $book = Book::first();
628 $this->setEntityRestrictions($book, []);
630 $bookChapter = $book->chapters->first();
631 $bookPage = $bookChapter->pages->first();
632 $this->setEntityRestrictions($bookPage, ['view']);
634 $this->actingAs($this->viewer);
635 $this->get($bookPage->getUrl());
636 $this->assertResponseOk();
637 $this->see($bookPage->name);
638 $this->dontSee(substr($book->name, 0, 15));
639 $this->dontSee(substr($bookChapter->name, 0, 15));
642 public function test_book_sort_view_permission()
644 $firstBook = Book::first();
645 $secondBook = Book::find(2);
646 $thirdBook = Book::find(3);
648 $this->setEntityRestrictions($firstBook, ['view', 'update']);
649 $this->setEntityRestrictions($secondBook, ['view']);
650 $this->setEntityRestrictions($thirdBook, ['view', 'update']);
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')
659 ->see($thirdBook->name)
660 ->dontSee($secondBook->name);
663 public function test_book_sort_permission() {
664 $firstBook = Book::first();
665 $secondBook = Book::find(2);
667 $this->setEntityRestrictions($firstBook, ['view', 'update']);
668 $this->setEntityRestrictions($secondBook, ['view']);
670 $firstBookChapter = $this->app[EntityRepo::class]->createFromInput('chapter',
671 ['name' => 'first book chapter'], $firstBook);
672 $secondBookChapter = $this->app[EntityRepo::class]->createFromInput('chapter',
673 ['name' => 'second book chapter'], $secondBook);
675 // Create request data
678 'id' => $firstBookChapter->id,
680 'parentChapter' => false,
682 'book' => $secondBook->id
686 // Move chapter from first book to a second book
687 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
689 ->see('You do not have permission')
694 'id' => $secondBookChapter->id,
696 'parentChapter' => false,
698 'book' => $firstBook->id
702 // Move chapter from second book to first book
703 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
705 ->see('You do not have permission')
709 public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
711 $book = Book::first();
712 $this->setEntityRestrictions($book, []);
713 $bookChapter = $book->chapters->first();
714 $this->setEntityRestrictions($bookChapter, ['view']);
716 $this->actingAs($this->user)->visit($bookChapter->getUrl())
717 ->dontSee('New Page');
719 $this->setEntityRestrictions($bookChapter, ['view', 'create']);
721 $this->actingAs($this->user)->visit($bookChapter->getUrl())
724 ->type('test page', 'name')
725 ->type('test content', 'html')
727 ->seePageIs($book->getUrl('/page/test-page'))
728 ->seeStatusCode(200);