]> BookStack Code Mirror - bookstack/blob - tests/Permissions/EntityPermissionsTest.php
Cleaned up dark mode styles inc. setting browser color scheme
[bookstack] / tests / Permissions / EntityPermissionsTest.php
1 <?php
2
3 namespace Tests\Permissions;
4
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 Exception;
12 use Illuminate\Support\Str;
13 use Tests\TestCase;
14
15 class EntityPermissionsTest extends TestCase
16 {
17     protected User $user;
18     protected User $viewer;
19
20     protected function setUp(): void
21     {
22         parent::setUp();
23         $this->user = $this->getEditor();
24         $this->viewer = $this->getViewer();
25     }
26
27     protected function setRestrictionsForTestRoles(Entity $entity, array $actions = [])
28     {
29         $roles = [
30             $this->user->roles->first(),
31             $this->viewer->roles->first(),
32         ];
33         $this->entities->setPermissions($entity, $actions, $roles);
34     }
35
36     public function test_bookshelf_view_restriction()
37     {
38         $shelf = $this->entities->shelf();
39
40         $this->actingAs($this->user)
41             ->get($shelf->getUrl())
42             ->assertStatus(200);
43
44         $this->setRestrictionsForTestRoles($shelf, []);
45
46         $this->followingRedirects()->get($shelf->getUrl())
47             ->assertSee('Shelf not found');
48
49         $this->setRestrictionsForTestRoles($shelf, ['view']);
50
51         $this->get($shelf->getUrl())
52             ->assertSee($shelf->name);
53     }
54
55     public function test_bookshelf_update_restriction()
56     {
57         $shelf = $this->entities->shelf();
58
59         $this->actingAs($this->user)
60             ->get($shelf->getUrl('/edit'))
61             ->assertSee('Edit Shelf');
62
63         $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
64
65         $resp = $this->get($shelf->getUrl('/edit'))
66             ->assertRedirect('/');
67         $this->followRedirects($resp)->assertSee('You do not have permission');
68
69         $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
70
71         $this->get($shelf->getUrl('/edit'))
72             ->assertOk();
73     }
74
75     public function test_bookshelf_delete_restriction()
76     {
77         $shelf = $this->entities->shelf();
78
79         $this->actingAs($this->user)
80             ->get($shelf->getUrl('/delete'))
81             ->assertSee('Delete Shelf');
82
83         $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
84
85         $this->get($shelf->getUrl('/delete'))->assertRedirect('/');
86         $this->get('/')->assertSee('You do not have permission');
87
88         $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
89
90         $this->get($shelf->getUrl('/delete'))
91             ->assertOk()
92             ->assertSee('Delete Shelf');
93     }
94
95     public function test_book_view_restriction()
96     {
97         $book = $this->entities->book();
98         $bookPage = $book->pages->first();
99         $bookChapter = $book->chapters->first();
100
101         $bookUrl = $book->getUrl();
102         $this->actingAs($this->user)
103             ->get($bookUrl)
104             ->assertOk();
105
106         $this->setRestrictionsForTestRoles($book, []);
107
108         $this->followingRedirects()->get($bookUrl)
109             ->assertSee('Book not found');
110         $this->followingRedirects()->get($bookPage->getUrl())
111             ->assertSee('Page not found');
112         $this->followingRedirects()->get($bookChapter->getUrl())
113             ->assertSee('Chapter not found');
114
115         $this->setRestrictionsForTestRoles($book, ['view']);
116
117         $this->get($bookUrl)
118             ->assertSee($book->name);
119         $this->get($bookPage->getUrl())
120             ->assertSee($bookPage->name);
121         $this->get($bookChapter->getUrl())
122             ->assertSee($bookChapter->name);
123     }
124
125     public function test_book_create_restriction()
126     {
127         $book = $this->entities->book();
128
129         $bookUrl = $book->getUrl();
130         $resp = $this->actingAs($this->viewer)->get($bookUrl);
131         $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
132             ->assertElementNotContains('.actions', 'New Chapter');
133         $resp = $this->actingAs($this->user)->get($bookUrl);
134         $this->withHtml($resp)->assertElementContains('.actions', 'New Page')
135             ->assertElementContains('.actions', 'New Chapter');
136
137         $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
138
139         $this->get($bookUrl . '/create-chapter')->assertRedirect('/');
140         $this->get('/')->assertSee('You do not have permission');
141
142         $this->get($bookUrl . '/create-page')->assertRedirect('/');
143         $this->get('/')->assertSee('You do not have permission');
144
145         $resp = $this->get($bookUrl);
146         $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
147             ->assertElementNotContains('.actions', 'New Chapter');
148
149         $this->setRestrictionsForTestRoles($book, ['view', 'create']);
150
151         $resp = $this->post($book->getUrl('/create-chapter'), [
152             'name'        => 'test chapter',
153             'description' => 'desc',
154         ]);
155         $resp->assertRedirect($book->getUrl('/chapter/test-chapter'));
156
157         $this->get($book->getUrl('/create-page'));
158         /** @var Page $page */
159         $page = Page::query()->where('draft', '=', true)->orderBy('id', 'desc')->first();
160         $resp = $this->post($page->getUrl(), [
161             'name' => 'test page',
162             'html' => 'test content',
163         ]);
164         $resp->assertRedirect($book->getUrl('/page/test-page'));
165
166         $resp = $this->get($bookUrl);
167         $this->withHtml($resp)->assertElementContains('.actions', 'New Page')
168             ->assertElementContains('.actions', 'New Chapter');
169     }
170
171     public function test_book_update_restriction()
172     {
173         $book = $this->entities->book();
174         $bookPage = $book->pages->first();
175         $bookChapter = $book->chapters->first();
176
177         $bookUrl = $book->getUrl();
178         $this->actingAs($this->user)
179             ->get($bookUrl . '/edit')
180             ->assertSee('Edit Book');
181
182         $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
183
184         $this->get($bookUrl . '/edit')->assertRedirect('/');
185         $this->get('/')->assertSee('You do not have permission');
186         $this->get($bookPage->getUrl() . '/edit')->assertRedirect('/');
187         $this->get('/')->assertSee('You do not have permission');
188         $this->get($bookChapter->getUrl() . '/edit')->assertRedirect('/');
189         $this->get('/')->assertSee('You do not have permission');
190
191         $this->setRestrictionsForTestRoles($book, ['view', 'update']);
192
193         $this->get($bookUrl . '/edit')->assertOk();
194         $this->get($bookPage->getUrl() . '/edit')->assertOk();
195         $this->get($bookChapter->getUrl() . '/edit')->assertSee('Edit Chapter');
196     }
197
198     public function test_book_delete_restriction()
199     {
200         $book = $this->entities->book();
201         $bookPage = $book->pages->first();
202         $bookChapter = $book->chapters->first();
203
204         $bookUrl = $book->getUrl();
205         $this->actingAs($this->user)->get($bookUrl . '/delete')
206             ->assertSee('Delete Book');
207
208         $this->setRestrictionsForTestRoles($book, ['view', 'update']);
209
210         $this->get($bookUrl . '/delete')->assertRedirect('/');
211         $this->get('/')->assertSee('You do not have permission');
212         $this->get($bookPage->getUrl() . '/delete')->assertRedirect('/');
213         $this->get('/')->assertSee('You do not have permission');
214         $this->get($bookChapter->getUrl() . '/delete')->assertRedirect('/');
215         $this->get('/')->assertSee('You do not have permission');
216
217         $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
218
219         $this->get($bookUrl . '/delete')->assertOk()->assertSee('Delete Book');
220         $this->get($bookPage->getUrl('/delete'))->assertOk()->assertSee('Delete Page');
221         $this->get($bookChapter->getUrl('/delete'))->assertSee('Delete Chapter');
222     }
223
224     public function test_chapter_view_restriction()
225     {
226         $chapter = $this->entities->chapter();
227         $chapterPage = $chapter->pages->first();
228
229         $chapterUrl = $chapter->getUrl();
230         $this->actingAs($this->user)->get($chapterUrl)->assertOk();
231
232         $this->setRestrictionsForTestRoles($chapter, []);
233
234         $this->followingRedirects()->get($chapterUrl)->assertSee('Chapter not found');
235         $this->followingRedirects()->get($chapterPage->getUrl())->assertSee('Page not found');
236
237         $this->setRestrictionsForTestRoles($chapter, ['view']);
238
239         $this->get($chapterUrl)->assertSee($chapter->name);
240         $this->get($chapterPage->getUrl())->assertSee($chapterPage->name);
241     }
242
243     public function test_chapter_create_restriction()
244     {
245         $chapter = $this->entities->chapter();
246
247         $chapterUrl = $chapter->getUrl();
248         $resp = $this->actingAs($this->user)->get($chapterUrl);
249         $this->withHtml($resp)->assertElementContains('.actions', 'New Page');
250
251         $this->setRestrictionsForTestRoles($chapter, ['view', 'delete', 'update']);
252
253         $this->get($chapterUrl . '/create-page')->assertRedirect('/');
254         $this->get('/')->assertSee('You do not have permission');
255         $this->withHtml($this->get($chapterUrl))->assertElementNotContains('.actions', 'New Page');
256
257         $this->setRestrictionsForTestRoles($chapter, ['view', 'create']);
258
259         $this->get($chapter->getUrl('/create-page'));
260         /** @var Page $page */
261         $page = Page::query()->where('draft', '=', true)->orderBy('id', 'desc')->first();
262         $resp = $this->post($page->getUrl(), [
263             'name' => 'test page',
264             'html' => 'test content',
265         ]);
266         $resp->assertRedirect($chapter->book->getUrl('/page/test-page'));
267
268         $this->withHtml($this->get($chapterUrl))->assertElementContains('.actions', 'New Page');
269     }
270
271     public function test_chapter_update_restriction()
272     {
273         $chapter = $this->entities->chapter();
274         $chapterPage = $chapter->pages->first();
275
276         $chapterUrl = $chapter->getUrl();
277         $this->actingAs($this->user)->get($chapterUrl . '/edit')
278             ->assertSee('Edit Chapter');
279
280         $this->setRestrictionsForTestRoles($chapter, ['view', 'delete']);
281
282         $this->get($chapterUrl . '/edit')->assertRedirect('/');
283         $this->get('/')->assertSee('You do not have permission');
284         $this->get($chapterPage->getUrl() . '/edit')->assertRedirect('/');
285         $this->get('/')->assertSee('You do not have permission');
286
287         $this->setRestrictionsForTestRoles($chapter, ['view', 'update']);
288
289         $this->get($chapterUrl . '/edit')->assertOk()->assertSee('Edit Chapter');
290         $this->get($chapterPage->getUrl() . '/edit')->assertOk();
291     }
292
293     public function test_chapter_delete_restriction()
294     {
295         $chapter = $this->entities->chapter();
296         $chapterPage = $chapter->pages->first();
297
298         $chapterUrl = $chapter->getUrl();
299         $this->actingAs($this->user)
300             ->get($chapterUrl . '/delete')
301             ->assertSee('Delete Chapter');
302
303         $this->setRestrictionsForTestRoles($chapter, ['view', 'update']);
304
305         $this->get($chapterUrl . '/delete')->assertRedirect('/');
306         $this->get('/')->assertSee('You do not have permission');
307         $this->get($chapterPage->getUrl() . '/delete')->assertRedirect('/');
308         $this->get('/')->assertSee('You do not have permission');
309
310         $this->setRestrictionsForTestRoles($chapter, ['view', 'delete']);
311
312         $this->get($chapterUrl . '/delete')->assertOk()->assertSee('Delete Chapter');
313         $this->get($chapterPage->getUrl() . '/delete')->assertOk()->assertSee('Delete Page');
314     }
315
316     public function test_page_view_restriction()
317     {
318         $page = $this->entities->page();
319
320         $pageUrl = $page->getUrl();
321         $this->actingAs($this->user)->get($pageUrl)->assertOk();
322
323         $this->setRestrictionsForTestRoles($page, ['update', 'delete']);
324
325         $this->get($pageUrl)->assertSee('Page not found');
326
327         $this->setRestrictionsForTestRoles($page, ['view']);
328
329         $this->get($pageUrl)->assertSee($page->name);
330     }
331
332     public function test_page_update_restriction()
333     {
334         $page = $this->entities->page();
335
336         $pageUrl = $page->getUrl();
337         $resp = $this->actingAs($this->user)
338             ->get($pageUrl . '/edit');
339         $this->withHtml($resp)->assertElementExists('input[name="name"][value="' . $page->name . '"]');
340
341         $this->setRestrictionsForTestRoles($page, ['view', 'delete']);
342
343         $this->get($pageUrl . '/edit')->assertRedirect('/');
344         $this->get('/')->assertSee('You do not have permission');
345
346         $this->setRestrictionsForTestRoles($page, ['view', 'update']);
347
348         $resp = $this->get($pageUrl . '/edit')
349             ->assertOk();
350         $this->withHtml($resp)->assertElementExists('input[name="name"][value="' . $page->name . '"]');
351     }
352
353     public function test_page_delete_restriction()
354     {
355         $page = $this->entities->page();
356
357         $pageUrl = $page->getUrl();
358         $this->actingAs($this->user)
359             ->get($pageUrl . '/delete')
360             ->assertSee('Delete Page');
361
362         $this->setRestrictionsForTestRoles($page, ['view', 'update']);
363
364         $this->get($pageUrl . '/delete')->assertRedirect('/');
365         $this->get('/')->assertSee('You do not have permission');
366
367         $this->setRestrictionsForTestRoles($page, ['view', 'delete']);
368
369         $this->get($pageUrl . '/delete')->assertOk()->assertSee('Delete Page');
370     }
371
372     protected function entityRestrictionFormTest(string $model, string $title, string $permission, string $roleId)
373     {
374         /** @var Entity $modelInstance */
375         $modelInstance = $model::query()->first();
376         $this->asAdmin()->get($modelInstance->getUrl('/permissions'))
377             ->assertSee($title);
378
379         $this->put($modelInstance->getUrl('/permissions'), [
380             'permissions' => [
381                 $roleId => [
382                     $permission => 'true',
383                 ],
384             ],
385         ]);
386
387         $this->assertDatabaseHas('entity_permissions', [
388             'entity_id'   => $modelInstance->id,
389             'entity_type' => $modelInstance->getMorphClass(),
390             'role_id'           => $roleId,
391             $permission         => true,
392         ]);
393     }
394
395     public function test_bookshelf_restriction_form()
396     {
397         $this->entityRestrictionFormTest(Bookshelf::class, 'Shelf Permissions', 'view', '2');
398     }
399
400     public function test_book_restriction_form()
401     {
402         $this->entityRestrictionFormTest(Book::class, 'Book Permissions', 'view', '2');
403     }
404
405     public function test_chapter_restriction_form()
406     {
407         $this->entityRestrictionFormTest(Chapter::class, 'Chapter Permissions', 'update', '2');
408     }
409
410     public function test_page_restriction_form()
411     {
412         $this->entityRestrictionFormTest(Page::class, 'Page Permissions', 'delete', '2');
413     }
414
415     public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
416     {
417         $chapter = $this->entities->chapter();
418         $page = $chapter->pages->first();
419         $page2 = $chapter->pages[2];
420
421         $this->setRestrictionsForTestRoles($page, []);
422
423         $resp = $this->actingAs($this->user)->get($page2->getUrl());
424         $this->withHtml($resp)->assertElementNotContains('.sidebar-page-list', $page->name);
425     }
426
427     public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
428     {
429         $chapter = $this->entities->chapter();
430         $page = $chapter->pages->first();
431
432         $this->setRestrictionsForTestRoles($page, []);
433
434         $resp = $this->actingAs($this->user)->get($chapter->getUrl());
435         $this->withHtml($resp)->assertElementNotContains('.sidebar-page-list', $page->name);
436     }
437
438     public function test_restricted_pages_not_visible_on_chapter_pages()
439     {
440         $chapter = $this->entities->chapter();
441         $page = $chapter->pages->first();
442
443         $this->setRestrictionsForTestRoles($page, []);
444
445         $this->actingAs($this->user)
446             ->get($chapter->getUrl())
447             ->assertDontSee($page->name);
448     }
449
450     public function test_restricted_chapter_pages_not_visible_on_book_page()
451     {
452         $chapter = $this->entities->chapter();
453         $this->actingAs($this->user)
454             ->get($chapter->book->getUrl())
455             ->assertSee($chapter->pages->first()->name);
456
457         foreach ($chapter->pages as $page) {
458             $this->setRestrictionsForTestRoles($page, []);
459         }
460
461         $this->actingAs($this->user)
462             ->get($chapter->book->getUrl())
463             ->assertDontSee($chapter->pages->first()->name);
464     }
465
466     public function test_bookshelf_update_restriction_override()
467     {
468         $shelf = $this->entities->shelf();
469
470         $this->actingAs($this->viewer)
471             ->get($shelf->getUrl('/edit'))
472             ->assertDontSee('Edit Book');
473
474         $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
475
476         $this->get($shelf->getUrl('/edit'))->assertRedirect('/');
477         $this->get('/')->assertSee('You do not have permission');
478
479         $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
480
481         $this->get($shelf->getUrl('/edit'))->assertOk();
482     }
483
484     public function test_bookshelf_delete_restriction_override()
485     {
486         $shelf = $this->entities->shelf();
487
488         $this->actingAs($this->viewer)
489             ->get($shelf->getUrl('/delete'))
490             ->assertDontSee('Delete Book');
491
492         $this->setRestrictionsForTestRoles($shelf, ['view', 'update']);
493
494         $this->get($shelf->getUrl('/delete'))->assertRedirect('/');
495         $this->get('/')->assertSee('You do not have permission');
496
497         $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']);
498
499         $this->get($shelf->getUrl('/delete'))->assertOk()->assertSee('Delete Shelf');
500     }
501
502     public function test_book_create_restriction_override()
503     {
504         $book = $this->entities->book();
505
506         $bookUrl = $book->getUrl();
507         $resp = $this->actingAs($this->viewer)->get($bookUrl);
508         $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
509             ->assertElementNotContains('.actions', 'New Chapter');
510
511         $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']);
512
513         $this->get($bookUrl . '/create-chapter')->assertRedirect('/');
514         $this->get('/')->assertSee('You do not have permission');
515         $this->get($bookUrl . '/create-page')->assertRedirect('/');
516         $this->get('/')->assertSee('You do not have permission');
517         $resp = $this->get($bookUrl);
518         $this->withHtml($resp)->assertElementNotContains('.actions', 'New Page')
519             ->assertElementNotContains('.actions', 'New Chapter');
520
521         $this->setRestrictionsForTestRoles($book, ['view', 'create']);
522
523         $resp = $this->post($book->getUrl('/create-chapter'), [
524             'name'        => 'test chapter',
525             'description' => 'test desc',
526         ]);
527         $resp->assertRedirect($book->getUrl('/chapter/test-chapter'));
528
529         $this->get($book->getUrl('/create-page'));
530         /** @var Page $page */
531         $page = Page::query()->where('draft', '=', true)->orderByDesc('id')->first();
532         $resp = $this->post($page->getUrl(), [
533             'name' => 'test page',
534             'html' => 'test desc',
535         ]);
536         $resp->assertRedirect($book->getUrl('/page/test-page'));
537
538         $resp = $this->get($bookUrl);
539         $this->withHtml($resp)->assertElementContains('.actions', 'New Page')
540             ->assertElementContains('.actions', 'New Chapter');
541     }
542
543     public function test_book_update_restriction_override()
544     {
545         $book = $this->entities->book();
546         $bookPage = $book->pages->first();
547         $bookChapter = $book->chapters->first();
548
549         $bookUrl = $book->getUrl();
550         $this->actingAs($this->viewer)->get($bookUrl . '/edit')
551             ->assertDontSee('Edit Book');
552
553         $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
554
555         $this->get($bookUrl . '/edit')->assertRedirect('/');
556         $this->get('/')->assertSee('You do not have permission');
557         $this->get($bookPage->getUrl() . '/edit')->assertRedirect('/');
558         $this->get('/')->assertSee('You do not have permission');
559         $this->get($bookChapter->getUrl() . '/edit')->assertRedirect('/');
560         $this->get('/')->assertSee('You do not have permission');
561
562         $this->setRestrictionsForTestRoles($book, ['view', 'update']);
563
564         $this->get($bookUrl . '/edit')->assertOk();
565         $this->get($bookPage->getUrl() . '/edit')->assertOk();
566         $this->get($bookChapter->getUrl() . '/edit')->assertSee('Edit Chapter');
567     }
568
569     public function test_book_delete_restriction_override()
570     {
571         $book = $this->entities->book();
572         $bookPage = $book->pages->first();
573         $bookChapter = $book->chapters->first();
574
575         $bookUrl = $book->getUrl();
576         $this->actingAs($this->viewer)
577             ->get($bookUrl . '/delete')
578             ->assertDontSee('Delete Book');
579
580         $this->setRestrictionsForTestRoles($book, ['view', 'update']);
581
582         $this->get($bookUrl . '/delete')->assertRedirect('/');
583         $this->get('/')->assertSee('You do not have permission');
584         $this->get($bookPage->getUrl() . '/delete')->assertRedirect('/');
585         $this->get('/')->assertSee('You do not have permission');
586         $this->get($bookChapter->getUrl() . '/delete')->assertRedirect('/');
587         $this->get('/')->assertSee('You do not have permission');
588
589         $this->setRestrictionsForTestRoles($book, ['view', 'delete']);
590
591         $this->get($bookUrl . '/delete')->assertOk()->assertSee('Delete Book');
592         $this->get($bookPage->getUrl() . '/delete')->assertOk()->assertSee('Delete Page');
593         $this->get($bookChapter->getUrl() . '/delete')->assertSee('Delete Chapter');
594     }
595
596     public function test_page_visible_if_has_permissions_when_book_not_visible()
597     {
598         $book = $this->entities->book();
599         $bookChapter = $book->chapters->first();
600         $bookPage = $bookChapter->pages->first();
601
602         foreach ([$book, $bookChapter, $bookPage] as $entity) {
603             $entity->name = Str::random(24);
604             $entity->save();
605         }
606
607         $this->setRestrictionsForTestRoles($book, []);
608         $this->setRestrictionsForTestRoles($bookPage, ['view']);
609
610         $this->actingAs($this->viewer);
611         $resp = $this->get($bookPage->getUrl());
612         $resp->assertOk();
613         $resp->assertSee($bookPage->name);
614         $resp->assertDontSee(substr($book->name, 0, 15));
615         $resp->assertDontSee(substr($bookChapter->name, 0, 15));
616     }
617
618     public function test_book_sort_view_permission()
619     {
620         /** @var Book $firstBook */
621         $firstBook = Book::query()->first();
622         /** @var Book $secondBook */
623         $secondBook = Book::query()->find(2);
624
625         $this->setRestrictionsForTestRoles($firstBook, ['view', 'update']);
626         $this->setRestrictionsForTestRoles($secondBook, ['view']);
627
628         // Test sort page visibility
629         $this->actingAs($this->user)->get($secondBook->getUrl('/sort'))->assertRedirect('/');
630         $this->get('/')->assertSee('You do not have permission');
631
632         // Check sort page on first book
633         $this->actingAs($this->user)->get($firstBook->getUrl('/sort'));
634     }
635
636     public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
637     {
638         $book = $this->entities->book();
639         $this->setRestrictionsForTestRoles($book, []);
640         $bookChapter = $book->chapters->first();
641         $this->setRestrictionsForTestRoles($bookChapter, ['view']);
642
643         $this->actingAs($this->user)->get($bookChapter->getUrl())
644             ->assertDontSee('New Page');
645
646         $this->setRestrictionsForTestRoles($bookChapter, ['view', 'create']);
647
648         $this->get($bookChapter->getUrl('/create-page'));
649         /** @var Page $page */
650         $page = Page::query()->where('draft', '=', true)->orderByDesc('id')->first();
651         $resp = $this->post($page->getUrl(), [
652             'name' => 'test page',
653             'html' => 'test content',
654         ]);
655         $resp->assertRedirect($book->getUrl('/page/test-page'));
656     }
657
658     public function test_book_permissions_can_be_generated_without_error_if_child_chapter_is_in_recycle_bin()
659     {
660         $book = $this->entities->bookHasChaptersAndPages();
661         /** @var Chapter $chapter */
662         $chapter = $book->chapters()->first();
663
664         $this->asAdmin()->delete($chapter->getUrl());
665
666         $error = null;
667         try {
668             $this->entities->setPermissions($book, ['view'], []);
669         } catch (Exception $e) {
670             $error = $e;
671         }
672
673         $this->assertNull($error);
674     }
675 }