3 namespace Tests\Permissions;
5 use BookStack\Auth\User;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Bookshelf;
8 use BookStack\Entities\Models\Chapter;
9 use BookStack\Entities\Models\Entity;
10 use BookStack\Entities\Models\Page;
11 use Illuminate\Support\Str;
12 use Tests\BrowserKitTest;
14 class EntityPermissionsTest extends BrowserKitTest
26 public function setUp(): void
29 $this->user = $this->getEditor();
30 $this->viewer = $this->getViewer();
33 protected function setRestrictionsForTestRoles(Entity $entity, array $actions = [])
36 $this->user->roles->first(),
37 $this->viewer->roles->first(),
39 $this->setEntityRestrictions($entity, $actions, $roles);
42 public function test_bookshelf_view_restriction()
44 $shelf = Bookshelf::first();
46 $this->actingAs($this->user)
47 ->visit($shelf->getUrl())
48 ->seePageIs($shelf->getUrl());
50 $this->setRestrictionsForTestRoles($shelf, []);
52 $this->forceVisit($shelf->getUrl())
53 ->see('Bookshelf not found');
55 $this->setRestrictionsForTestRoles($shelf, ['view']);
57 $this->visit($shelf->getUrl())
61 public function test_bookshelf_update_restriction()
63 $shelf = Bookshelf::first();
65 $this->actingAs($this->user)
66 ->visit($shelf->getUrl('/edit'))
69 $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
71 $this->forceVisit($shelf->getUrl('/edit'))
72 ->see('You do not have permission')->seePageIs('/');
74 $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
76 $this->visit($shelf->getUrl('/edit'))
77 ->seePageIs($shelf->getUrl('/edit'));
80 public function test_bookshelf_delete_restriction()
82 $shelf = Book::first();
84 $this->actingAs($this->user)
85 ->visit($shelf->getUrl('/delete'))
88 $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
90 $this->forceVisit($shelf->getUrl('/delete'))
91 ->see('You do not have permission')->seePageIs('/');
93 $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
95 $this->visit($shelf->getUrl('/delete'))
96 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
99 public function test_book_view_restriction()
101 $book = Book::first();
102 $bookPage = $book->pages->first();
103 $bookChapter = $book->chapters->first();
105 $bookUrl = $book->getUrl();
106 $this->actingAs($this->user)
108 ->seePageIs($bookUrl);
110 $this->setRestrictionsForTestRoles($book, []);
112 $this->forceVisit($bookUrl)
113 ->see('Book not found');
114 $this->forceVisit($bookPage->getUrl())
115 ->see('Page not found');
116 $this->forceVisit($bookChapter->getUrl())
117 ->see('Chapter not found');
119 $this->setRestrictionsForTestRoles($book, ['view']);
121 $this->visit($bookUrl)
123 $this->visit($bookPage->getUrl())
124 ->see($bookPage->name);
125 $this->visit($bookChapter->getUrl())
126 ->see($bookChapter->name);
129 public function test_book_create_restriction()
131 $book = Book::first();
133 $bookUrl = $book->getUrl();
134 $this->actingAs($this->viewer)
136 ->dontSeeInElement('.actions', 'New Page')
137 ->dontSeeInElement('.actions', 'New Chapter');
138 $this->actingAs($this->user)
140 ->seeInElement('.actions', 'New Page')
141 ->seeInElement('.actions', 'New Chapter');
143 $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
145 $this->forceVisit($bookUrl . '/create-chapter')
146 ->see('You do not have permission')->seePageIs('/');
147 $this->forceVisit($bookUrl . '/create-page')
148 ->see('You do not have permission')->seePageIs('/');
149 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
150 ->dontSeeInElement('.actions', 'New Chapter');
152 $this->setRestrictionsForTestRoles($book, ['view', 'create']);
154 $this->visit($bookUrl . '/create-chapter')
155 ->type('test chapter', 'name')
156 ->type('test description for chapter', 'description')
157 ->press('Save Chapter')
158 ->seePageIs($bookUrl . '/chapter/test-chapter');
159 $this->visit($bookUrl . '/create-page')
160 ->type('test page', 'name')
161 ->type('test content', 'html')
163 ->seePageIs($bookUrl . '/page/test-page');
164 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
165 ->seeInElement('.actions', 'New Chapter');
168 public function test_book_update_restriction()
170 $book = Book::first();
171 $bookPage = $book->pages->first();
172 $bookChapter = $book->chapters->first();
174 $bookUrl = $book->getUrl();
175 $this->actingAs($this->user)
176 ->visit($bookUrl . '/edit')
179 $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
181 $this->forceVisit($bookUrl . '/edit')
182 ->see('You do not have permission')->seePageIs('/');
183 $this->forceVisit($bookPage->getUrl() . '/edit')
184 ->see('You do not have permission')->seePageIs('/');
185 $this->forceVisit($bookChapter->getUrl() . '/edit')
186 ->see('You do not have permission')->seePageIs('/');
188 $this->setRestrictionsForTestRoles($book, ['view', 'update']);
190 $this->visit($bookUrl . '/edit')
191 ->seePageIs($bookUrl . '/edit');
192 $this->visit($bookPage->getUrl() . '/edit')
193 ->seePageIs($bookPage->getUrl() . '/edit');
194 $this->visit($bookChapter->getUrl() . '/edit')
195 ->see('Edit Chapter');
198 public function test_book_delete_restriction()
200 $book = Book::first();
201 $bookPage = $book->pages->first();
202 $bookChapter = $book->chapters->first();
204 $bookUrl = $book->getUrl();
205 $this->actingAs($this->user)
206 ->visit($bookUrl . '/delete')
207 ->see('Delete Book');
209 $this->setRestrictionsForTestRoles($book, ['view', 'update']);
211 $this->forceVisit($bookUrl . '/delete')
212 ->see('You do not have permission')->seePageIs('/');
213 $this->forceVisit($bookPage->getUrl() . '/delete')
214 ->see('You do not have permission')->seePageIs('/');
215 $this->forceVisit($bookChapter->getUrl() . '/delete')
216 ->see('You do not have permission')->seePageIs('/');
218 $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
220 $this->visit($bookUrl . '/delete')
221 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
222 $this->visit($bookPage->getUrl() . '/delete')
223 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
224 $this->visit($bookChapter->getUrl() . '/delete')
225 ->see('Delete Chapter');
228 public function test_chapter_view_restriction()
230 $chapter = Chapter::first();
231 $chapterPage = $chapter->pages->first();
233 $chapterUrl = $chapter->getUrl();
234 $this->actingAs($this->user)
236 ->seePageIs($chapterUrl);
238 $this->setRestrictionsForTestRoles($chapter, []);
240 $this->forceVisit($chapterUrl)
241 ->see('Chapter not found');
242 $this->forceVisit($chapterPage->getUrl())
243 ->see('Page not found');
245 $this->setRestrictionsForTestRoles($chapter, ['view']);
247 $this->visit($chapterUrl)
248 ->see($chapter->name);
249 $this->visit($chapterPage->getUrl())
250 ->see($chapterPage->name);
253 public function test_chapter_create_restriction()
255 $chapter = Chapter::first();
257 $chapterUrl = $chapter->getUrl();
258 $this->actingAs($this->user)
260 ->seeInElement('.actions', 'New Page');
262 $this->setRestrictionsForTestRoles($chapter, ['view', 'delete', 'update']);
264 $this->forceVisit($chapterUrl . '/create-page')
265 ->see('You do not have permission')->seePageIs('/');
266 $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page');
268 $this->setRestrictionsForTestRoles($chapter, ['view', 'create']);
270 $this->visit($chapterUrl . '/create-page')
271 ->type('test page', 'name')
272 ->type('test content', 'html')
274 ->seePageIs($chapter->book->getUrl() . '/page/test-page');
276 $this->visit($chapterUrl)->seeInElement('.actions', 'New Page');
279 public function test_chapter_update_restriction()
281 $chapter = Chapter::first();
282 $chapterPage = $chapter->pages->first();
284 $chapterUrl = $chapter->getUrl();
285 $this->actingAs($this->user)
286 ->visit($chapterUrl . '/edit')
287 ->see('Edit Chapter');
289 $this->setRestrictionsForTestRoles($chapter, ['view', 'delete']);
291 $this->forceVisit($chapterUrl . '/edit')
292 ->see('You do not have permission')->seePageIs('/');
293 $this->forceVisit($chapterPage->getUrl() . '/edit')
294 ->see('You do not have permission')->seePageIs('/');
296 $this->setRestrictionsForTestRoles($chapter, ['view', 'update']);
298 $this->visit($chapterUrl . '/edit')
299 ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter');
300 $this->visit($chapterPage->getUrl() . '/edit')
301 ->seePageIs($chapterPage->getUrl() . '/edit');
304 public function test_chapter_delete_restriction()
306 $chapter = Chapter::first();
307 $chapterPage = $chapter->pages->first();
309 $chapterUrl = $chapter->getUrl();
310 $this->actingAs($this->user)
311 ->visit($chapterUrl . '/delete')
312 ->see('Delete Chapter');
314 $this->setRestrictionsForTestRoles($chapter, ['view', 'update']);
316 $this->forceVisit($chapterUrl . '/delete')
317 ->see('You do not have permission')->seePageIs('/');
318 $this->forceVisit($chapterPage->getUrl() . '/delete')
319 ->see('You do not have permission')->seePageIs('/');
321 $this->setRestrictionsForTestRoles($chapter, ['view', 'delete']);
323 $this->visit($chapterUrl . '/delete')
324 ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter');
325 $this->visit($chapterPage->getUrl() . '/delete')
326 ->seePageIs($chapterPage->getUrl() . '/delete')->see('Delete Page');
329 public function test_page_view_restriction()
331 $page = Page::first();
333 $pageUrl = $page->getUrl();
334 $this->actingAs($this->user)
336 ->seePageIs($pageUrl);
338 $this->setRestrictionsForTestRoles($page, ['update', 'delete']);
340 $this->forceVisit($pageUrl)
341 ->see('Page not found');
343 $this->setRestrictionsForTestRoles($page, ['view']);
345 $this->visit($pageUrl)
349 public function test_page_update_restriction()
351 $page = Chapter::first();
353 $pageUrl = $page->getUrl();
354 $this->actingAs($this->user)
355 ->visit($pageUrl . '/edit')
356 ->seeInField('name', $page->name);
358 $this->setRestrictionsForTestRoles($page, ['view', 'delete']);
360 $this->forceVisit($pageUrl . '/edit')
361 ->see('You do not have permission')->seePageIs('/');
363 $this->setRestrictionsForTestRoles($page, ['view', 'update']);
365 $this->visit($pageUrl . '/edit')
366 ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name);
369 public function test_page_delete_restriction()
371 $page = Page::first();
373 $pageUrl = $page->getUrl();
374 $this->actingAs($this->user)
375 ->visit($pageUrl . '/delete')
376 ->see('Delete Page');
378 $this->setRestrictionsForTestRoles($page, ['view', 'update']);
380 $this->forceVisit($pageUrl . '/delete')
381 ->see('You do not have permission')->seePageIs('/');
383 $this->setRestrictionsForTestRoles($page, ['view', 'delete']);
385 $this->visit($pageUrl . '/delete')
386 ->seePageIs($pageUrl . '/delete')->see('Delete Page');
389 public function test_bookshelf_restriction_form()
391 $shelf = Bookshelf::first();
392 $this->asAdmin()->visit($shelf->getUrl('/permissions'))
393 ->see('Bookshelf Permissions')
394 ->check('restricted')
395 ->check('restrictions[2][view]')
396 ->press('Save Permissions')
397 ->seeInDatabase('bookshelves', ['id' => $shelf->id, 'restricted' => true])
398 ->seeInDatabase('entity_permissions', [
399 'restrictable_id' => $shelf->id,
400 'restrictable_type' => Bookshelf::newModelInstance()->getMorphClass(),
406 public function test_book_restriction_form()
408 $book = Book::first();
409 $this->asAdmin()->visit($book->getUrl() . '/permissions')
410 ->see('Book Permissions')
411 ->check('restricted')
412 ->check('restrictions[2][view]')
413 ->press('Save Permissions')
414 ->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
415 ->seeInDatabase('entity_permissions', [
416 'restrictable_id' => $book->id,
417 'restrictable_type' => Book::newModelInstance()->getMorphClass(),
423 public function test_chapter_restriction_form()
425 $chapter = Chapter::first();
426 $this->asAdmin()->visit($chapter->getUrl() . '/permissions')
427 ->see('Chapter Permissions')
428 ->check('restricted')
429 ->check('restrictions[2][update]')
430 ->press('Save Permissions')
431 ->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
432 ->seeInDatabase('entity_permissions', [
433 'restrictable_id' => $chapter->id,
434 'restrictable_type' => Chapter::newModelInstance()->getMorphClass(),
436 'action' => 'update',
440 public function test_page_restriction_form()
442 $page = Page::first();
443 $this->asAdmin()->visit($page->getUrl() . '/permissions')
444 ->see('Page Permissions')
445 ->check('restricted')
446 ->check('restrictions[2][delete]')
447 ->press('Save Permissions')
448 ->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
449 ->seeInDatabase('entity_permissions', [
450 'restrictable_id' => $page->id,
451 'restrictable_type' => Page::newModelInstance()->getMorphClass(),
453 'action' => 'delete',
457 public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
459 $chapter = Chapter::first();
460 $page = $chapter->pages->first();
461 $page2 = $chapter->pages[2];
463 $this->setRestrictionsForTestRoles($page, []);
465 $this->actingAs($this->user)
466 ->visit($page2->getUrl())
467 ->dontSeeInElement('.sidebar-page-list', $page->name);
470 public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
472 $chapter = Chapter::first();
473 $page = $chapter->pages->first();
475 $this->setRestrictionsForTestRoles($page, []);
477 $this->actingAs($this->user)
478 ->visit($chapter->getUrl())
479 ->dontSeeInElement('.sidebar-page-list', $page->name);
482 public function test_restricted_pages_not_visible_on_chapter_pages()
484 $chapter = Chapter::first();
485 $page = $chapter->pages->first();
487 $this->setRestrictionsForTestRoles($page, []);
489 $this->actingAs($this->user)
490 ->visit($chapter->getUrl())
491 ->dontSee($page->name);
494 public function test_restricted_chapter_pages_not_visible_on_book_page()
496 $chapter = Chapter::query()->first();
497 $this->actingAs($this->user)
498 ->visit($chapter->book->getUrl())
499 ->see($chapter->pages->first()->name);
501 foreach ($chapter->pages as $page) {
502 $this->setRestrictionsForTestRoles($page, []);
505 $this->actingAs($this->user)
506 ->visit($chapter->book->getUrl())
507 ->dontSee($chapter->pages->first()->name);
510 public function test_bookshelf_update_restriction_override()
512 $shelf = Bookshelf::first();
514 $this->actingAs($this->viewer)
515 ->visit($shelf->getUrl('/edit'))
516 ->dontSee('Edit Book');
518 $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
520 $this->forceVisit($shelf->getUrl('/edit'))
521 ->see('You do not have permission')->seePageIs('/');
523 $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
525 $this->visit($shelf->getUrl('/edit'))
526 ->seePageIs($shelf->getUrl('/edit'));
529 public function test_bookshelf_delete_restriction_override()
531 $shelf = Bookshelf::first();
533 $this->actingAs($this->viewer)
534 ->visit($shelf->getUrl('/delete'))
535 ->dontSee('Delete Book');
537 $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
539 $this->forceVisit($shelf->getUrl('/delete'))
540 ->see('You do not have permission')->seePageIs('/');
542 $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
544 $this->visit($shelf->getUrl('/delete'))
545 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
548 public function test_book_create_restriction_override()
550 $book = Book::first();
552 $bookUrl = $book->getUrl();
553 $this->actingAs($this->viewer)
555 ->dontSeeInElement('.actions', 'New Page')
556 ->dontSeeInElement('.actions', 'New Chapter');
558 $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
560 $this->forceVisit($bookUrl . '/create-chapter')
561 ->see('You do not have permission')->seePageIs('/');
562 $this->forceVisit($bookUrl . '/create-page')
563 ->see('You do not have permission')->seePageIs('/');
564 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
565 ->dontSeeInElement('.actions', 'New Chapter');
567 $this->setRestrictionsForTestRoles($book, ['view', 'create']);
569 $this->visit($bookUrl . '/create-chapter')
570 ->type('test chapter', 'name')
571 ->type('test description for chapter', 'description')
572 ->press('Save Chapter')
573 ->seePageIs($bookUrl . '/chapter/test-chapter');
574 $this->visit($bookUrl . '/create-page')
575 ->type('test page', 'name')
576 ->type('test content', 'html')
578 ->seePageIs($bookUrl . '/page/test-page');
579 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
580 ->seeInElement('.actions', 'New Chapter');
583 public function test_book_update_restriction_override()
585 $book = Book::first();
586 $bookPage = $book->pages->first();
587 $bookChapter = $book->chapters->first();
589 $bookUrl = $book->getUrl();
590 $this->actingAs($this->viewer)
591 ->visit($bookUrl . '/edit')
592 ->dontSee('Edit Book');
594 $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
596 $this->forceVisit($bookUrl . '/edit')
597 ->see('You do not have permission')->seePageIs('/');
598 $this->forceVisit($bookPage->getUrl() . '/edit')
599 ->see('You do not have permission')->seePageIs('/');
600 $this->forceVisit($bookChapter->getUrl() . '/edit')
601 ->see('You do not have permission')->seePageIs('/');
603 $this->setRestrictionsForTestRoles($book, ['view', 'update']);
605 $this->visit($bookUrl . '/edit')
606 ->seePageIs($bookUrl . '/edit');
607 $this->visit($bookPage->getUrl() . '/edit')
608 ->seePageIs($bookPage->getUrl() . '/edit');
609 $this->visit($bookChapter->getUrl() . '/edit')
610 ->see('Edit Chapter');
613 public function test_book_delete_restriction_override()
615 $book = Book::first();
616 $bookPage = $book->pages->first();
617 $bookChapter = $book->chapters->first();
619 $bookUrl = $book->getUrl();
620 $this->actingAs($this->viewer)
621 ->visit($bookUrl . '/delete')
622 ->dontSee('Delete Book');
624 $this->setRestrictionsForTestRoles($book, ['view', 'update']);
626 $this->forceVisit($bookUrl . '/delete')
627 ->see('You do not have permission')->seePageIs('/');
628 $this->forceVisit($bookPage->getUrl() . '/delete')
629 ->see('You do not have permission')->seePageIs('/');
630 $this->forceVisit($bookChapter->getUrl() . '/delete')
631 ->see('You do not have permission')->seePageIs('/');
633 $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
635 $this->visit($bookUrl . '/delete')
636 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
637 $this->visit($bookPage->getUrl() . '/delete')
638 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
639 $this->visit($bookChapter->getUrl() . '/delete')
640 ->see('Delete Chapter');
643 public function test_page_visible_if_has_permissions_when_book_not_visible()
645 $book = Book::first();
646 $bookChapter = $book->chapters->first();
647 $bookPage = $bookChapter->pages->first();
649 foreach ([$book, $bookChapter, $bookPage] as $entity) {
650 $entity->name = Str::random(24);
654 $this->setRestrictionsForTestRoles($book, []);
655 $this->setRestrictionsForTestRoles($bookPage, ['view']);
657 $this->actingAs($this->viewer);
658 $this->get($bookPage->getUrl());
659 $this->assertResponseOk();
660 $this->see($bookPage->name);
661 $this->dontSee(substr($book->name, 0, 15));
662 $this->dontSee(substr($bookChapter->name, 0, 15));
665 public function test_book_sort_view_permission()
667 $firstBook = Book::first();
668 $secondBook = Book::find(2);
670 $this->setRestrictionsForTestRoles($firstBook, ['view', 'update']);
671 $this->setRestrictionsForTestRoles($secondBook, ['view']);
673 // Test sort page visibility
674 $this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort')
675 ->see('You do not have permission')
678 // Check sort page on first book
679 $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort');
682 public function test_book_sort_permission()
684 $firstBook = Book::first();
685 $secondBook = Book::find(2);
687 $this->setRestrictionsForTestRoles($firstBook, ['view', 'update']);
688 $this->setRestrictionsForTestRoles($secondBook, ['view']);
690 $firstBookChapter = $this->newChapter(['name' => 'first book chapter'], $firstBook);
691 $secondBookChapter = $this->newChapter(['name' => 'second book chapter'], $secondBook);
693 // Create request data
696 'id' => $firstBookChapter->id,
698 'parentChapter' => false,
700 'book' => $secondBook->id,
704 // Move chapter from first book to a second book
705 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
707 ->see('You do not have permission')
712 'id' => $secondBookChapter->id,
714 'parentChapter' => false,
716 'book' => $firstBook->id,
720 // Move chapter from second book to first book
721 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
723 ->see('You do not have permission')
727 public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
729 $book = Book::first();
730 $this->setRestrictionsForTestRoles($book, []);
731 $bookChapter = $book->chapters->first();
732 $this->setRestrictionsForTestRoles($bookChapter, ['view']);
734 $this->actingAs($this->user)->visit($bookChapter->getUrl())
735 ->dontSee('New Page');
737 $this->setRestrictionsForTestRoles($bookChapter, ['view', 'create']);
739 $this->actingAs($this->user)->visit($bookChapter->getUrl())
742 ->type('test page', 'name')
743 ->type('test content', 'html')
745 ->seePageIs($book->getUrl('/page/test-page'))
746 ->seeStatusCode(200);