1 <?php namespace Tests\Permissions;
3 use BookStack\Entities\Models\Book;
4 use BookStack\Entities\Models\Bookshelf;
5 use BookStack\Entities\Models\Chapter;
6 use BookStack\Entities\Models\Entity;
7 use BookStack\Auth\User;
8 use BookStack\Entities\Models\Page;
9 use Illuminate\Support\Str;
10 use Tests\BrowserKitTest;
12 class EntityPermissionsTest extends BrowserKitTest
25 public function setUp(): void
28 $this->user = $this->getEditor();
29 $this->viewer = $this->getViewer();
32 protected function setRestrictionsForTestRoles(Entity $entity, array $actions = [])
35 $this->user->roles->first(),
36 $this->viewer->roles->first(),
38 $this->setEntityRestrictions($entity, $actions, $roles);
41 public function test_bookshelf_view_restriction()
43 $shelf = Bookshelf::first();
45 $this->actingAs($this->user)
46 ->visit($shelf->getUrl())
47 ->seePageIs($shelf->getUrl());
49 $this->setRestrictionsForTestRoles($shelf, []);
51 $this->forceVisit($shelf->getUrl())
52 ->see('Bookshelf not found');
54 $this->setRestrictionsForTestRoles($shelf, ['view']);
56 $this->visit($shelf->getUrl())
60 public function test_bookshelf_update_restriction()
62 $shelf = Bookshelf::first();
64 $this->actingAs($this->user)
65 ->visit($shelf->getUrl('/edit'))
68 $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
70 $this->forceVisit($shelf->getUrl('/edit'))
71 ->see('You do not have permission')->seePageIs('/');
73 $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
75 $this->visit($shelf->getUrl('/edit'))
76 ->seePageIs($shelf->getUrl('/edit'));
79 public function test_bookshelf_delete_restriction()
81 $shelf = Book::first();
83 $this->actingAs($this->user)
84 ->visit($shelf->getUrl('/delete'))
87 $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
89 $this->forceVisit($shelf->getUrl('/delete'))
90 ->see('You do not have permission')->seePageIs('/');
92 $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
94 $this->visit($shelf->getUrl('/delete'))
95 ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book');
98 public function test_book_view_restriction()
100 $book = Book::first();
101 $bookPage = $book->pages->first();
102 $bookChapter = $book->chapters->first();
104 $bookUrl = $book->getUrl();
105 $this->actingAs($this->user)
107 ->seePageIs($bookUrl);
109 $this->setRestrictionsForTestRoles($book, []);
111 $this->forceVisit($bookUrl)
112 ->see('Book not found');
113 $this->forceVisit($bookPage->getUrl())
114 ->see('Page not found');
115 $this->forceVisit($bookChapter->getUrl())
116 ->see('Chapter not found');
118 $this->setRestrictionsForTestRoles($book, ['view']);
120 $this->visit($bookUrl)
122 $this->visit($bookPage->getUrl())
123 ->see($bookPage->name);
124 $this->visit($bookChapter->getUrl())
125 ->see($bookChapter->name);
128 public function test_book_create_restriction()
130 $book = Book::first();
132 $bookUrl = $book->getUrl();
133 $this->actingAs($this->viewer)
135 ->dontSeeInElement('.actions', 'New Page')
136 ->dontSeeInElement('.actions', 'New Chapter');
137 $this->actingAs($this->user)
139 ->seeInElement('.actions', 'New Page')
140 ->seeInElement('.actions', 'New Chapter');
142 $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
144 $this->forceVisit($bookUrl . '/create-chapter')
145 ->see('You do not have permission')->seePageIs('/');
146 $this->forceVisit($bookUrl . '/create-page')
147 ->see('You do not have permission')->seePageIs('/');
148 $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page')
149 ->dontSeeInElement('.actions', 'New Chapter');
151 $this->setRestrictionsForTestRoles($book, ['view', 'create']);
153 $this->visit($bookUrl . '/create-chapter')
154 ->type('test chapter', 'name')
155 ->type('test description for chapter', 'description')
156 ->press('Save Chapter')
157 ->seePageIs($bookUrl . '/chapter/test-chapter');
158 $this->visit($bookUrl . '/create-page')
159 ->type('test page', 'name')
160 ->type('test content', 'html')
162 ->seePageIs($bookUrl . '/page/test-page');
163 $this->visit($bookUrl)->seeInElement('.actions', 'New Page')
164 ->seeInElement('.actions', 'New Chapter');
167 public function test_book_update_restriction()
169 $book = Book::first();
170 $bookPage = $book->pages->first();
171 $bookChapter = $book->chapters->first();
173 $bookUrl = $book->getUrl();
174 $this->actingAs($this->user)
175 ->visit($bookUrl . '/edit')
178 $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
180 $this->forceVisit($bookUrl . '/edit')
181 ->see('You do not have permission')->seePageIs('/');
182 $this->forceVisit($bookPage->getUrl() . '/edit')
183 ->see('You do not have permission')->seePageIs('/');
184 $this->forceVisit($bookChapter->getUrl() . '/edit')
185 ->see('You do not have permission')->seePageIs('/');
187 $this->setRestrictionsForTestRoles($book, ['view', 'update']);
189 $this->visit($bookUrl . '/edit')
190 ->seePageIs($bookUrl . '/edit');
191 $this->visit($bookPage->getUrl() . '/edit')
192 ->seePageIs($bookPage->getUrl() . '/edit');
193 $this->visit($bookChapter->getUrl() . '/edit')
194 ->see('Edit Chapter');
197 public function test_book_delete_restriction()
199 $book = Book::first();
200 $bookPage = $book->pages->first();
201 $bookChapter = $book->chapters->first();
203 $bookUrl = $book->getUrl();
204 $this->actingAs($this->user)
205 ->visit($bookUrl . '/delete')
206 ->see('Delete Book');
208 $this->setRestrictionsForTestRoles($book, ['view', 'update']);
210 $this->forceVisit($bookUrl . '/delete')
211 ->see('You do not have permission')->seePageIs('/');
212 $this->forceVisit($bookPage->getUrl() . '/delete')
213 ->see('You do not have permission')->seePageIs('/');
214 $this->forceVisit($bookChapter->getUrl() . '/delete')
215 ->see('You do not have permission')->seePageIs('/');
217 $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
219 $this->visit($bookUrl . '/delete')
220 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
221 $this->visit($bookPage->getUrl() . '/delete')
222 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
223 $this->visit($bookChapter->getUrl() . '/delete')
224 ->see('Delete Chapter');
227 public function test_chapter_view_restriction()
229 $chapter = Chapter::first();
230 $chapterPage = $chapter->pages->first();
232 $chapterUrl = $chapter->getUrl();
233 $this->actingAs($this->user)
235 ->seePageIs($chapterUrl);
237 $this->setRestrictionsForTestRoles($chapter, []);
239 $this->forceVisit($chapterUrl)
240 ->see('Chapter not found');
241 $this->forceVisit($chapterPage->getUrl())
242 ->see('Page not found');
244 $this->setRestrictionsForTestRoles($chapter, ['view']);
246 $this->visit($chapterUrl)
247 ->see($chapter->name);
248 $this->visit($chapterPage->getUrl())
249 ->see($chapterPage->name);
252 public function test_chapter_create_restriction()
254 $chapter = Chapter::first();
256 $chapterUrl = $chapter->getUrl();
257 $this->actingAs($this->user)
259 ->seeInElement('.actions', 'New Page');
261 $this->setRestrictionsForTestRoles($chapter, ['view', 'delete', 'update']);
263 $this->forceVisit($chapterUrl . '/create-page')
264 ->see('You do not have permission')->seePageIs('/');
265 $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page');
267 $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(),
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(),
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() {
683 $firstBook = Book::first();
684 $secondBook = Book::find(2);
686 $this->setRestrictionsForTestRoles($firstBook, ['view', 'update']);
687 $this->setRestrictionsForTestRoles($secondBook, ['view']);
689 $firstBookChapter = $this->newChapter(['name' => 'first book chapter'], $firstBook);
690 $secondBookChapter = $this->newChapter(['name' => 'second book chapter'], $secondBook);
692 // Create request data
695 'id' => $firstBookChapter->id,
697 'parentChapter' => false,
699 'book' => $secondBook->id
703 // Move chapter from first book to a second book
704 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
706 ->see('You do not have permission')
711 'id' => $secondBookChapter->id,
713 'parentChapter' => false,
715 'book' => $firstBook->id
719 // Move chapter from second book to first book
720 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
722 ->see('You do not have permission')
726 public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
728 $book = Book::first();
729 $this->setRestrictionsForTestRoles($book, []);
730 $bookChapter = $book->chapters->first();
731 $this->setRestrictionsForTestRoles($bookChapter, ['view']);
733 $this->actingAs($this->user)->visit($bookChapter->getUrl())
734 ->dontSee('New Page');
736 $this->setRestrictionsForTestRoles($bookChapter, ['view', 'create']);
738 $this->actingAs($this->user)->visit($bookChapter->getUrl())
741 ->type('test page', 'name')
742 ->type('test content', 'html')
744 ->seePageIs($book->getUrl('/page/test-page'))
745 ->seeStatusCode(200);