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\Page;
10 class RestrictionsTest extends BrowserKitTest
23 public function setUp(): void
26 $this->user = $this->getEditor();
27 $this->viewer = $this->getViewer();
30 protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = [])
33 $this->user->roles->first(),
34 $this->viewer->roles->first(),
36 parent::setEntityRestrictions($entity, $actions, $roles);
39 public function test_bookshelf_view_restriction()
41 $shelf = Bookshelf::first();
43 $this->actingAs($this->user)
44 ->visit($shelf->getUrl())
45 ->seePageIs($shelf->getUrl());
47 $this->setEntityRestrictions($shelf, []);
49 $this->forceVisit($shelf->getUrl())
50 ->see('Bookshelf not found');
52 $this->setEntityRestrictions($shelf, ['view']);
54 $this->visit($shelf->getUrl())
58 public function test_bookshelf_update_restriction()
60 $shelf = BookShelf::first();
62 $this->actingAs($this->user)
63 ->visit($shelf->getUrl('/edit'))
66 $this->setEntityRestrictions($shelf, ['view', 'delete']);
68 $this->forceVisit($shelf->getUrl('/edit'))
69 ->see('You do not have permission')->seePageIs('/');
71 $this->setEntityRestrictions($shelf, ['view', 'update']);
73 $this->visit($shelf->getUrl('/edit'))
74 ->seePageIs($shelf->getUrl('/edit'));
77 public function test_bookshelf_delete_restriction()
79 $shelf = Book::first();
81 $this->actingAs($this->user)
82 ->visit($shelf->getUrl('/delete'))
85 $this->setEntityRestrictions($shelf, ['view', 'update']);
87 $this->forceVisit($shelf->getUrl('/delete'))
88 ->see('You do not have permission')->seePageIs('/');
90 $this->setEntityRestrictions($shelf, ['view', 'delete']);
92 $this->visit($shelf->getUrl('/delete'))
93 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
96 public function test_book_view_restriction()
98 $book = Book::first();
99 $bookPage = $book->pages->first();
100 $bookChapter = $book->chapters->first();
102 $bookUrl = $book->getUrl();
103 $this->actingAs($this->user)
105 ->seePageIs($bookUrl);
107 $this->setEntityRestrictions($book, []);
109 $this->forceVisit($bookUrl)
110 ->see('Book not found');
111 $this->forceVisit($bookPage->getUrl())
112 ->see('Page not found');
113 $this->forceVisit($bookChapter->getUrl())
114 ->see('Chapter not found');
116 $this->setEntityRestrictions($book, ['view']);
118 $this->visit($bookUrl)
120 $this->visit($bookPage->getUrl())
121 ->see($bookPage->name);
122 $this->visit($bookChapter->getUrl())
123 ->see($bookChapter->name);
126 public function test_book_create_restriction()
128 $book = Book::first();
130 $bookUrl = $book->getUrl();
131 $this->actingAs($this->viewer)
133 ->dontSeeInElement('.actions', 'New Page')
134 ->dontSeeInElement('.actions', 'New Chapter');
135 $this->actingAs($this->user)
137 ->seeInElement('.actions', 'New Page')
138 ->seeInElement('.actions', 'New Chapter');
140 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
142 $this->forceVisit($bookUrl . '/create-chapter')
143 ->see('You do not have permission')->seePageIs('/');
144 $this->forceVisit($bookUrl . '/create-page')
145 ->see('You do not have permission')->seePageIs('/');
146 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
147 ->dontSeeInElement('.actions', 'New Chapter');
149 $this->setEntityRestrictions($book, ['view', 'create']);
151 $this->visit($bookUrl . '/create-chapter')
152 ->type('test chapter', 'name')
153 ->type('test description for chapter', 'description')
154 ->press('Save Chapter')
155 ->seePageIs($bookUrl . '/chapter/test-chapter');
156 $this->visit($bookUrl . '/create-page')
157 ->type('test page', 'name')
158 ->type('test content', 'html')
160 ->seePageIs($bookUrl . '/page/test-page');
161 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
162 ->seeInElement('.actions', 'New Chapter');
165 public function test_book_update_restriction()
167 $book = Book::first();
168 $bookPage = $book->pages->first();
169 $bookChapter = $book->chapters->first();
171 $bookUrl = $book->getUrl();
172 $this->actingAs($this->user)
173 ->visit($bookUrl . '/edit')
176 $this->setEntityRestrictions($book, ['view', 'delete']);
178 $this->forceVisit($bookUrl . '/edit')
179 ->see('You do not have permission')->seePageIs('/');
180 $this->forceVisit($bookPage->getUrl() . '/edit')
181 ->see('You do not have permission')->seePageIs('/');
182 $this->forceVisit($bookChapter->getUrl() . '/edit')
183 ->see('You do not have permission')->seePageIs('/');
185 $this->setEntityRestrictions($book, ['view', 'update']);
187 $this->visit($bookUrl . '/edit')
188 ->seePageIs($bookUrl . '/edit');
189 $this->visit($bookPage->getUrl() . '/edit')
190 ->seePageIs($bookPage->getUrl() . '/edit');
191 $this->visit($bookChapter->getUrl() . '/edit')
192 ->see('Edit Chapter');
195 public function test_book_delete_restriction()
197 $book = Book::first();
198 $bookPage = $book->pages->first();
199 $bookChapter = $book->chapters->first();
201 $bookUrl = $book->getUrl();
202 $this->actingAs($this->user)
203 ->visit($bookUrl . '/delete')
204 ->see('Delete Book');
206 $this->setEntityRestrictions($book, ['view', 'update']);
208 $this->forceVisit($bookUrl . '/delete')
209 ->see('You do not have permission')->seePageIs('/');
210 $this->forceVisit($bookPage->getUrl() . '/delete')
211 ->see('You do not have permission')->seePageIs('/');
212 $this->forceVisit($bookChapter->getUrl() . '/delete')
213 ->see('You do not have permission')->seePageIs('/');
215 $this->setEntityRestrictions($book, ['view', 'delete']);
217 $this->visit($bookUrl . '/delete')
218 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
219 $this->visit($bookPage->getUrl() . '/delete')
220 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
221 $this->visit($bookChapter->getUrl() . '/delete')
222 ->see('Delete Chapter');
225 public function test_chapter_view_restriction()
227 $chapter = Chapter::first();
228 $chapterPage = $chapter->pages->first();
230 $chapterUrl = $chapter->getUrl();
231 $this->actingAs($this->user)
233 ->seePageIs($chapterUrl);
235 $this->setEntityRestrictions($chapter, []);
237 $this->forceVisit($chapterUrl)
238 ->see('Chapter not found');
239 $this->forceVisit($chapterPage->getUrl())
240 ->see('Page not found');
242 $this->setEntityRestrictions($chapter, ['view']);
244 $this->visit($chapterUrl)
245 ->see($chapter->name);
246 $this->visit($chapterPage->getUrl())
247 ->see($chapterPage->name);
250 public function test_chapter_create_restriction()
252 $chapter = Chapter::first();
254 $chapterUrl = $chapter->getUrl();
255 $this->actingAs($this->user)
257 ->seeInElement('.actions', 'New Page');
259 $this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
261 $this->forceVisit($chapterUrl . '/create-page')
262 ->see('You do not have permission')->seePageIs('/');
263 $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page');
265 $this->setEntityRestrictions($chapter, ['view', 'create']);
268 $this->visit($chapterUrl . '/create-page')
269 ->type('test page', 'name')
270 ->type('test content', 'html')
272 ->seePageIs($chapter->book->getUrl() . '/page/test-page');
274 $this->visit($chapterUrl)->seeInElement('.actions', 'New Page');
277 public function test_chapter_update_restriction()
279 $chapter = Chapter::first();
280 $chapterPage = $chapter->pages->first();
282 $chapterUrl = $chapter->getUrl();
283 $this->actingAs($this->user)
284 ->visit($chapterUrl . '/edit')
285 ->see('Edit Chapter');
287 $this->setEntityRestrictions($chapter, ['view', 'delete']);
289 $this->forceVisit($chapterUrl . '/edit')
290 ->see('You do not have permission')->seePageIs('/');
291 $this->forceVisit($chapterPage->getUrl() . '/edit')
292 ->see('You do not have permission')->seePageIs('/');
294 $this->setEntityRestrictions($chapter, ['view', 'update']);
296 $this->visit($chapterUrl . '/edit')
297 ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter');
298 $this->visit($chapterPage->getUrl() . '/edit')
299 ->seePageIs($chapterPage->getUrl() . '/edit');
302 public function test_chapter_delete_restriction()
304 $chapter = Chapter::first();
305 $chapterPage = $chapter->pages->first();
307 $chapterUrl = $chapter->getUrl();
308 $this->actingAs($this->user)
309 ->visit($chapterUrl . '/delete')
310 ->see('Delete Chapter');
312 $this->setEntityRestrictions($chapter, ['view', 'update']);
314 $this->forceVisit($chapterUrl . '/delete')
315 ->see('You do not have permission')->seePageIs('/');
316 $this->forceVisit($chapterPage->getUrl() . '/delete')
317 ->see('You do not have permission')->seePageIs('/');
319 $this->setEntityRestrictions($chapter, ['view', 'delete']);
321 $this->visit($chapterUrl . '/delete')
322 ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter');
323 $this->visit($chapterPage->getUrl() . '/delete')
324 ->seePageIs($chapterPage->getUrl() . '/delete')->see('Delete Page');
327 public function test_page_view_restriction()
329 $page = Page::first();
331 $pageUrl = $page->getUrl();
332 $this->actingAs($this->user)
334 ->seePageIs($pageUrl);
336 $this->setEntityRestrictions($page, ['update', 'delete']);
338 $this->forceVisit($pageUrl)
339 ->see('Page not found');
341 $this->setEntityRestrictions($page, ['view']);
343 $this->visit($pageUrl)
347 public function test_page_update_restriction()
349 $page = Chapter::first();
351 $pageUrl = $page->getUrl();
352 $this->actingAs($this->user)
353 ->visit($pageUrl . '/edit')
354 ->seeInField('name', $page->name);
356 $this->setEntityRestrictions($page, ['view', 'delete']);
358 $this->forceVisit($pageUrl . '/edit')
359 ->see('You do not have permission')->seePageIs('/');
361 $this->setEntityRestrictions($page, ['view', 'update']);
363 $this->visit($pageUrl . '/edit')
364 ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name);
367 public function test_page_delete_restriction()
369 $page = Page::first();
371 $pageUrl = $page->getUrl();
372 $this->actingAs($this->user)
373 ->visit($pageUrl . '/delete')
374 ->see('Delete Page');
376 $this->setEntityRestrictions($page, ['view', 'update']);
378 $this->forceVisit($pageUrl . '/delete')
379 ->see('You do not have permission')->seePageIs('/');
381 $this->setEntityRestrictions($page, ['view', 'delete']);
383 $this->visit($pageUrl . '/delete')
384 ->seePageIs($pageUrl . '/delete')->see('Delete Page');
387 public function test_bookshelf_restriction_form()
389 $shelf = Bookshelf::first();
390 $this->asAdmin()->visit($shelf->getUrl('/permissions'))
391 ->see('Bookshelf Permissions')
392 ->check('restricted')
393 ->check('restrictions[2][view]')
394 ->press('Save Permissions')
395 ->seeInDatabase('bookshelves', ['id' => $shelf->id, 'restricted' => true])
396 ->seeInDatabase('entity_permissions', [
397 'restrictable_id' => $shelf->id,
398 'restrictable_type' => Bookshelf::newModelInstance()->getMorphClass(),
404 public function test_book_restriction_form()
406 $book = Book::first();
407 $this->asAdmin()->visit($book->getUrl() . '/permissions')
408 ->see('Book Permissions')
409 ->check('restricted')
410 ->check('restrictions[2][view]')
411 ->press('Save Permissions')
412 ->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
413 ->seeInDatabase('entity_permissions', [
414 'restrictable_id' => $book->id,
415 'restrictable_type' => Book::newModelInstance()->getMorphClass(),
421 public function test_chapter_restriction_form()
423 $chapter = Chapter::first();
424 $this->asAdmin()->visit($chapter->getUrl() . '/permissions')
425 ->see('Chapter Permissions')
426 ->check('restricted')
427 ->check('restrictions[2][update]')
428 ->press('Save Permissions')
429 ->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
430 ->seeInDatabase('entity_permissions', [
431 'restrictable_id' => $chapter->id,
432 'restrictable_type' => Chapter::newModelInstance()->getMorphClass(),
438 public function test_page_restriction_form()
440 $page = Page::first();
441 $this->asAdmin()->visit($page->getUrl() . '/permissions')
442 ->see('Page Permissions')
443 ->check('restricted')
444 ->check('restrictions[2][delete]')
445 ->press('Save Permissions')
446 ->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
447 ->seeInDatabase('entity_permissions', [
448 'restrictable_id' => $page->id,
449 'restrictable_type' => Page::newModelInstance()->getMorphClass(),
455 public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
457 $chapter = Chapter::first();
458 $page = $chapter->pages->first();
459 $page2 = $chapter->pages[2];
461 $this->setEntityRestrictions($page, []);
463 $this->actingAs($this->user)
464 ->visit($page2->getUrl())
465 ->dontSeeInElement('.sidebar-page-list', $page->name);
468 public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
470 $chapter = Chapter::first();
471 $page = $chapter->pages->first();
473 $this->setEntityRestrictions($page, []);
475 $this->actingAs($this->user)
476 ->visit($chapter->getUrl())
477 ->dontSeeInElement('.sidebar-page-list', $page->name);
480 public function test_restricted_pages_not_visible_on_chapter_pages()
482 $chapter = Chapter::first();
483 $page = $chapter->pages->first();
485 $this->setEntityRestrictions($page, []);
487 $this->actingAs($this->user)
488 ->visit($chapter->getUrl())
489 ->dontSee($page->name);
492 public function test_bookshelf_update_restriction_override()
494 $shelf = Bookshelf::first();
496 $this->actingAs($this->viewer)
497 ->visit($shelf->getUrl('/edit'))
498 ->dontSee('Edit Book');
500 $this->setEntityRestrictions($shelf, ['view', 'delete']);
502 $this->forceVisit($shelf->getUrl('/edit'))
503 ->see('You do not have permission')->seePageIs('/');
505 $this->setEntityRestrictions($shelf, ['view', 'update']);
507 $this->visit($shelf->getUrl('/edit'))
508 ->seePageIs($shelf->getUrl('/edit'));
511 public function test_bookshelf_delete_restriction_override()
513 $shelf = Bookshelf::first();
515 $this->actingAs($this->viewer)
516 ->visit($shelf->getUrl('/delete'))
517 ->dontSee('Delete Book');
519 $this->setEntityRestrictions($shelf, ['view', 'update']);
521 $this->forceVisit($shelf->getUrl('/delete'))
522 ->see('You do not have permission')->seePageIs('/');
524 $this->setEntityRestrictions($shelf, ['view', 'delete']);
526 $this->visit($shelf->getUrl('/delete'))
527 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
530 public function test_book_create_restriction_override()
532 $book = Book::first();
534 $bookUrl = $book->getUrl();
535 $this->actingAs($this->viewer)
537 ->dontSeeInElement('.actions', 'New Page')
538 ->dontSeeInElement('.actions', 'New Chapter');
540 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
542 $this->forceVisit($bookUrl . '/create-chapter')
543 ->see('You do not have permission')->seePageIs('/');
544 $this->forceVisit($bookUrl . '/create-page')
545 ->see('You do not have permission')->seePageIs('/');
546 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
547 ->dontSeeInElement('.actions', 'New Chapter');
549 $this->setEntityRestrictions($book, ['view', 'create']);
551 $this->visit($bookUrl . '/create-chapter')
552 ->type('test chapter', 'name')
553 ->type('test description for chapter', 'description')
554 ->press('Save Chapter')
555 ->seePageIs($bookUrl . '/chapter/test-chapter');
556 $this->visit($bookUrl . '/create-page')
557 ->type('test page', 'name')
558 ->type('test content', 'html')
560 ->seePageIs($bookUrl . '/page/test-page');
561 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
562 ->seeInElement('.actions', 'New Chapter');
565 public function test_book_update_restriction_override()
567 $book = Book::first();
568 $bookPage = $book->pages->first();
569 $bookChapter = $book->chapters->first();
571 $bookUrl = $book->getUrl();
572 $this->actingAs($this->viewer)
573 ->visit($bookUrl . '/edit')
574 ->dontSee('Edit Book');
576 $this->setEntityRestrictions($book, ['view', 'delete']);
578 $this->forceVisit($bookUrl . '/edit')
579 ->see('You do not have permission')->seePageIs('/');
580 $this->forceVisit($bookPage->getUrl() . '/edit')
581 ->see('You do not have permission')->seePageIs('/');
582 $this->forceVisit($bookChapter->getUrl() . '/edit')
583 ->see('You do not have permission')->seePageIs('/');
585 $this->setEntityRestrictions($book, ['view', 'update']);
587 $this->visit($bookUrl . '/edit')
588 ->seePageIs($bookUrl . '/edit');
589 $this->visit($bookPage->getUrl() . '/edit')
590 ->seePageIs($bookPage->getUrl() . '/edit');
591 $this->visit($bookChapter->getUrl() . '/edit')
592 ->see('Edit Chapter');
595 public function test_book_delete_restriction_override()
597 $book = Book::first();
598 $bookPage = $book->pages->first();
599 $bookChapter = $book->chapters->first();
601 $bookUrl = $book->getUrl();
602 $this->actingAs($this->viewer)
603 ->visit($bookUrl . '/delete')
604 ->dontSee('Delete Book');
606 $this->setEntityRestrictions($book, ['view', 'update']);
608 $this->forceVisit($bookUrl . '/delete')
609 ->see('You do not have permission')->seePageIs('/');
610 $this->forceVisit($bookPage->getUrl() . '/delete')
611 ->see('You do not have permission')->seePageIs('/');
612 $this->forceVisit($bookChapter->getUrl() . '/delete')
613 ->see('You do not have permission')->seePageIs('/');
615 $this->setEntityRestrictions($book, ['view', 'delete']);
617 $this->visit($bookUrl . '/delete')
618 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
619 $this->visit($bookPage->getUrl() . '/delete')
620 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
621 $this->visit($bookChapter->getUrl() . '/delete')
622 ->see('Delete Chapter');
625 public function test_page_visible_if_has_permissions_when_book_not_visible()
627 $book = Book::first();
629 $this->setEntityRestrictions($book, []);
631 $bookChapter = $book->chapters->first();
632 $bookPage = $bookChapter->pages->first();
633 $this->setEntityRestrictions($bookPage, ['view']);
635 $this->actingAs($this->viewer);
636 $this->get($bookPage->getUrl());
637 $this->assertResponseOk();
638 $this->see($bookPage->name);
639 $this->dontSee(substr($book->name, 0, 15));
640 $this->dontSee(substr($bookChapter->name, 0, 15));
643 public function test_book_sort_view_permission()
645 $firstBook = Book::first();
646 $secondBook = Book::find(2);
648 $this->setEntityRestrictions($firstBook, ['view', 'update']);
649 $this->setEntityRestrictions($secondBook, ['view']);
651 // Test sort page visibility
652 $this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort')
653 ->see('You do not have permission')
656 // Check sort page on first book
657 $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort');
660 public function test_book_sort_permission() {
661 $firstBook = Book::first();
662 $secondBook = Book::find(2);
664 $this->setEntityRestrictions($firstBook, ['view', 'update']);
665 $this->setEntityRestrictions($secondBook, ['view']);
667 $firstBookChapter = $this->newChapter(['name' => 'first book chapter'], $firstBook);
668 $secondBookChapter = $this->newChapter(['name' => 'second book chapter'], $secondBook);
670 // Create request data
673 'id' => $firstBookChapter->id,
675 'parentChapter' => false,
677 'book' => $secondBook->id
681 // Move chapter from first book to a second book
682 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
684 ->see('You do not have permission')
689 'id' => $secondBookChapter->id,
691 'parentChapter' => false,
693 'book' => $firstBook->id
697 // Move chapter from second book to first book
698 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
700 ->see('You do not have permission')
704 public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
706 $book = Book::first();
707 $this->setEntityRestrictions($book, []);
708 $bookChapter = $book->chapters->first();
709 $this->setEntityRestrictions($bookChapter, ['view']);
711 $this->actingAs($this->user)->visit($bookChapter->getUrl())
712 ->dontSee('New Page');
714 $this->setEntityRestrictions($bookChapter, ['view', 'create']);
716 $this->actingAs($this->user)->visit($bookChapter->getUrl())
719 ->type('test page', 'name')
720 ->type('test content', 'html')
722 ->seePageIs($book->getUrl('/page/test-page'))
723 ->seeStatusCode(200);