]> BookStack Code Mirror - bookstack/blob - tests/Permissions/RolesTest.php
Apply fixes from StyleCI
[bookstack] / tests / Permissions / RolesTest.php
1 <?php
2
3 namespace Tests\Permissions;
4
5 use BookStack\Actions\Comment;
6 use BookStack\Auth\Role;
7 use BookStack\Auth\User;
8 use BookStack\Entities\Models\Book;
9 use BookStack\Entities\Models\Bookshelf;
10 use BookStack\Entities\Models\Chapter;
11 use BookStack\Entities\Models\Page;
12 use BookStack\Uploads\Image;
13 use Laravel\BrowserKitTesting\HttpException;
14 use Tests\BrowserKitTest;
15
16 class RolesTest extends BrowserKitTest
17 {
18     protected $user;
19
20     public function setUp(): void
21     {
22         parent::setUp();
23         $this->user = $this->getViewer();
24     }
25
26     public function test_admin_can_see_settings()
27     {
28         $this->asAdmin()->visit('/settings')->see('Settings');
29     }
30
31     public function test_cannot_delete_admin_role()
32     {
33         $adminRole = Role::getRole('admin');
34         $deletePageUrl = '/settings/roles/delete/' . $adminRole->id;
35         $this->asAdmin()->visit($deletePageUrl)
36             ->press('Confirm')
37             ->seePageIs($deletePageUrl)
38             ->see('cannot be deleted');
39     }
40
41     public function test_role_cannot_be_deleted_if_default()
42     {
43         $newRole = $this->createNewRole();
44         $this->setSettings(['registration-role' => $newRole->id]);
45
46         $deletePageUrl = '/settings/roles/delete/' . $newRole->id;
47         $this->asAdmin()->visit($deletePageUrl)
48             ->press('Confirm')
49             ->seePageIs($deletePageUrl)
50             ->see('cannot be deleted');
51     }
52
53     public function test_role_create_update_delete_flow()
54     {
55         $testRoleName = 'Test Role';
56         $testRoleDesc = 'a little test description';
57         $testRoleUpdateName = 'An Super Updated role';
58
59         // Creation
60         $this->asAdmin()->visit('/settings')
61             ->click('Roles')
62             ->seePageIs('/settings/roles')
63             ->click('Create New Role')
64             ->type('Test Role', 'display_name')
65             ->type('A little test description', 'description')
66             ->press('Save Role')
67             ->seeInDatabase('roles', ['display_name' => $testRoleName, 'description' => $testRoleDesc])
68             ->seePageIs('/settings/roles');
69         // Updating
70         $this->asAdmin()->visit('/settings/roles')
71             ->see($testRoleDesc)
72             ->click($testRoleName)
73             ->type($testRoleUpdateName, '#display_name')
74             ->press('Save Role')
75             ->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'description' => $testRoleDesc])
76             ->seePageIs('/settings/roles');
77         // Deleting
78         $this->asAdmin()->visit('/settings/roles')
79             ->click($testRoleUpdateName)
80             ->click('Delete Role')
81             ->see($testRoleUpdateName)
82             ->press('Confirm')
83             ->seePageIs('/settings/roles')
84             ->dontSee($testRoleUpdateName);
85     }
86
87     public function test_admin_role_cannot_be_removed_if_last_admin()
88     {
89         $adminRole = Role::where('system_name', '=', 'admin')->first();
90         $adminUser = $this->getAdmin();
91         $adminRole->users()->where('id', '!=', $adminUser->id)->delete();
92         $this->assertEquals($adminRole->users()->count(), 1);
93
94         $viewerRole = $this->getViewer()->roles()->first();
95
96         $editUrl = '/settings/users/' . $adminUser->id;
97         $this->actingAs($adminUser)->put($editUrl, [
98             'name'  => $adminUser->name,
99             'email' => $adminUser->email,
100             'roles' => [
101                 'viewer' => strval($viewerRole->id),
102             ],
103         ])->followRedirects();
104
105         $this->seePageIs($editUrl);
106         $this->see('This user is the only user assigned to the administrator role');
107     }
108
109     public function test_migrate_users_on_delete_works()
110     {
111         $roleA = Role::query()->create(['display_name' => 'Delete Test A']);
112         $roleB = Role::query()->create(['display_name' => 'Delete Test B']);
113         $this->user->attachRole($roleB);
114
115         $this->assertCount(0, $roleA->users()->get());
116         $this->assertCount(1, $roleB->users()->get());
117
118         $deletePage = $this->asAdmin()->get("/settings/roles/delete/{$roleB->id}");
119         $deletePage->seeElement('select[name=migrate_role_id]');
120         $this->asAdmin()->delete("/settings/roles/delete/{$roleB->id}", [
121             'migrate_role_id' => $roleA->id,
122         ]);
123
124         $this->assertCount(1, $roleA->users()->get());
125         $this->assertEquals($this->user->id, $roleA->users()->first()->id);
126     }
127
128     public function test_manage_user_permission()
129     {
130         $this->actingAs($this->user)->visit('/settings/users')
131             ->seePageIs('/');
132         $this->giveUserPermissions($this->user, ['users-manage']);
133         $this->actingAs($this->user)->visit('/settings/users')
134             ->seePageIs('/settings/users');
135     }
136
137     public function test_manage_users_permission_shows_link_in_header_if_does_not_have_settings_manage_permision()
138     {
139         $usersLink = 'href="' . url('/settings/users') . '"';
140         $this->actingAs($this->user)->visit('/')->dontSee($usersLink);
141         $this->giveUserPermissions($this->user, ['users-manage']);
142         $this->actingAs($this->user)->visit('/')->see($usersLink);
143         $this->giveUserPermissions($this->user, ['settings-manage', 'users-manage']);
144         $this->actingAs($this->user)->visit('/')->dontSee($usersLink);
145     }
146
147     public function test_user_cannot_change_email_unless_they_have_manage_users_permission()
148     {
149         $userProfileUrl = '/settings/users/' . $this->user->id;
150         $originalEmail = $this->user->email;
151         $this->actingAs($this->user);
152
153         $this->visit($userProfileUrl)
154             ->assertResponseOk()
155             ->seeElement('input[name=email][disabled]');
156         $this->put($userProfileUrl, [
157             'name'  => 'my_new_name',
158             'email' => '[email protected]',
159         ]);
160         $this->seeInDatabase('users', [
161             'id'    => $this->user->id,
162             'email' => $originalEmail,
163             'name'  => 'my_new_name',
164         ]);
165
166         $this->giveUserPermissions($this->user, ['users-manage']);
167
168         $this->visit($userProfileUrl)
169             ->assertResponseOk()
170             ->dontSeeElement('input[name=email][disabled]')
171             ->seeElement('input[name=email]');
172         $this->put($userProfileUrl, [
173             'name'  => 'my_new_name_2',
174             'email' => '[email protected]',
175         ]);
176
177         $this->seeInDatabase('users', [
178             'id'    => $this->user->id,
179             'email' => '[email protected]',
180             'name'  => 'my_new_name_2',
181         ]);
182     }
183
184     public function test_user_roles_manage_permission()
185     {
186         $this->actingAs($this->user)->visit('/settings/roles')
187             ->seePageIs('/')->visit('/settings/roles/1')->seePageIs('/');
188         $this->giveUserPermissions($this->user, ['user-roles-manage']);
189         $this->actingAs($this->user)->visit('/settings/roles')
190             ->seePageIs('/settings/roles')->click('Admin')
191             ->see('Edit Role');
192     }
193
194     public function test_settings_manage_permission()
195     {
196         $this->actingAs($this->user)->visit('/settings')
197             ->seePageIs('/');
198         $this->giveUserPermissions($this->user, ['settings-manage']);
199         $this->actingAs($this->user)->visit('/settings')
200             ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved');
201     }
202
203     public function test_restrictions_manage_all_permission()
204     {
205         $page = Page::take(1)->get()->first();
206         $this->actingAs($this->user)->visit($page->getUrl())
207             ->dontSee('Permissions')
208             ->visit($page->getUrl() . '/permissions')
209             ->seePageIs('/');
210         $this->giveUserPermissions($this->user, ['restrictions-manage-all']);
211         $this->actingAs($this->user)->visit($page->getUrl())
212             ->see('Permissions')
213             ->click('Permissions')
214             ->see('Page Permissions')->seePageIs($page->getUrl() . '/permissions');
215     }
216
217     public function test_restrictions_manage_own_permission()
218     {
219         $otherUsersPage = Page::first();
220         $content = $this->createEntityChainBelongingToUser($this->user);
221
222         // Set a different creator on the page we're checking to ensure
223         // that the owner fields are checked
224         $page = $content['page']; /** @var Page $page */
225         $page->created_by = $otherUsersPage->id;
226         $page->owned_by = $this->user->id;
227         $page->save();
228
229         // Check can't restrict other's content
230         $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
231             ->dontSee('Permissions')
232             ->visit($otherUsersPage->getUrl() . '/permissions')
233             ->seePageIs('/');
234         // Check can't restrict own content
235         $this->actingAs($this->user)->visit($page->getUrl())
236             ->dontSee('Permissions')
237             ->visit($page->getUrl() . '/permissions')
238             ->seePageIs('/');
239
240         $this->giveUserPermissions($this->user, ['restrictions-manage-own']);
241
242         // Check can't restrict other's content
243         $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
244             ->dontSee('Permissions')
245             ->visit($otherUsersPage->getUrl() . '/permissions')
246             ->seePageIs('/');
247         // Check can restrict own content
248         $this->actingAs($this->user)->visit($page->getUrl())
249             ->see('Permissions')
250             ->click('Permissions')
251             ->seePageIs($page->getUrl() . '/permissions');
252     }
253
254     /**
255      * Check a standard entity access permission.
256      *
257      * @param string $permission
258      * @param array  $accessUrls Urls that are only accessible after having the permission
259      * @param array  $visibles   Check this text, In the buttons toolbar, is only visible with the permission
260      */
261     private function checkAccessPermission($permission, $accessUrls = [], $visibles = [])
262     {
263         foreach ($accessUrls as $url) {
264             $this->actingAs($this->user)->visit($url)
265                 ->seePageIs('/');
266         }
267         foreach ($visibles as $url => $text) {
268             $this->actingAs($this->user)->visit($url)
269                 ->dontSeeInElement('.action-buttons', $text);
270         }
271
272         $this->giveUserPermissions($this->user, [$permission]);
273
274         foreach ($accessUrls as $url) {
275             $this->actingAs($this->user)->visit($url)
276                 ->seePageIs($url);
277         }
278         foreach ($visibles as $url => $text) {
279             $this->actingAs($this->user)->visit($url)
280                 ->see($text);
281         }
282     }
283
284     public function test_bookshelves_create_all_permissions()
285     {
286         $this->checkAccessPermission('bookshelf-create-all', [
287             '/create-shelf',
288         ], [
289             '/shelves' => 'New Shelf',
290         ]);
291
292         $this->visit('/create-shelf')
293             ->type('test shelf', 'name')
294             ->type('shelf desc', 'description')
295             ->press('Save Shelf')
296             ->seePageIs('/shelves/test-shelf');
297     }
298
299     public function test_bookshelves_edit_own_permission()
300     {
301         $otherShelf = Bookshelf::first();
302         $ownShelf = $this->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
303         $ownShelf->forceFill(['owned_by' => $this->user->id, 'updated_by' => $this->user->id])->save();
304         $this->regenEntityPermissions($ownShelf);
305
306         $this->checkAccessPermission('bookshelf-update-own', [
307             $ownShelf->getUrl('/edit'),
308         ], [
309             $ownShelf->getUrl() => 'Edit',
310         ]);
311
312         $this->visit($otherShelf->getUrl())
313             ->dontSeeInElement('.action-buttons', 'Edit')
314             ->visit($otherShelf->getUrl('/edit'))
315             ->seePageIs('/');
316     }
317
318     public function test_bookshelves_edit_all_permission()
319     {
320         $otherShelf = Bookshelf::first();
321         $this->checkAccessPermission('bookshelf-update-all', [
322             $otherShelf->getUrl('/edit'),
323         ], [
324             $otherShelf->getUrl() => 'Edit',
325         ]);
326     }
327
328     public function test_bookshelves_delete_own_permission()
329     {
330         $this->giveUserPermissions($this->user, ['bookshelf-update-all']);
331         $otherShelf = Bookshelf::first();
332         $ownShelf = $this->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
333         $ownShelf->forceFill(['owned_by' => $this->user->id, 'updated_by' => $this->user->id])->save();
334         $this->regenEntityPermissions($ownShelf);
335
336         $this->checkAccessPermission('bookshelf-delete-own', [
337             $ownShelf->getUrl('/delete'),
338         ], [
339             $ownShelf->getUrl() => 'Delete',
340         ]);
341
342         $this->visit($otherShelf->getUrl())
343             ->dontSeeInElement('.action-buttons', 'Delete')
344             ->visit($otherShelf->getUrl('/delete'))
345             ->seePageIs('/');
346         $this->visit($ownShelf->getUrl())->visit($ownShelf->getUrl('/delete'))
347             ->press('Confirm')
348             ->seePageIs('/shelves')
349             ->dontSee($ownShelf->name);
350     }
351
352     public function test_bookshelves_delete_all_permission()
353     {
354         $this->giveUserPermissions($this->user, ['bookshelf-update-all']);
355         $otherShelf = Bookshelf::first();
356         $this->checkAccessPermission('bookshelf-delete-all', [
357             $otherShelf->getUrl('/delete'),
358         ], [
359             $otherShelf->getUrl() => 'Delete',
360         ]);
361
362         $this->visit($otherShelf->getUrl())->visit($otherShelf->getUrl('/delete'))
363             ->press('Confirm')
364             ->seePageIs('/shelves')
365             ->dontSee($otherShelf->name);
366     }
367
368     public function test_books_create_all_permissions()
369     {
370         $this->checkAccessPermission('book-create-all', [
371             '/create-book',
372         ], [
373             '/books' => 'Create New Book',
374         ]);
375
376         $this->visit('/create-book')
377             ->type('test book', 'name')
378             ->type('book desc', 'description')
379             ->press('Save Book')
380             ->seePageIs('/books/test-book');
381     }
382
383     public function test_books_edit_own_permission()
384     {
385         $otherBook = Book::take(1)->get()->first();
386         $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
387         $this->checkAccessPermission('book-update-own', [
388             $ownBook->getUrl() . '/edit',
389         ], [
390             $ownBook->getUrl() => 'Edit',
391         ]);
392
393         $this->visit($otherBook->getUrl())
394             ->dontSeeInElement('.action-buttons', 'Edit')
395             ->visit($otherBook->getUrl() . '/edit')
396             ->seePageIs('/');
397     }
398
399     public function test_books_edit_all_permission()
400     {
401         $otherBook = Book::take(1)->get()->first();
402         $this->checkAccessPermission('book-update-all', [
403             $otherBook->getUrl() . '/edit',
404         ], [
405             $otherBook->getUrl() => 'Edit',
406         ]);
407     }
408
409     public function test_books_delete_own_permission()
410     {
411         $this->giveUserPermissions($this->user, ['book-update-all']);
412         $otherBook = Book::take(1)->get()->first();
413         $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
414         $this->checkAccessPermission('book-delete-own', [
415             $ownBook->getUrl() . '/delete',
416         ], [
417             $ownBook->getUrl() => 'Delete',
418         ]);
419
420         $this->visit($otherBook->getUrl())
421             ->dontSeeInElement('.action-buttons', 'Delete')
422             ->visit($otherBook->getUrl() . '/delete')
423             ->seePageIs('/');
424         $this->visit($ownBook->getUrl())->visit($ownBook->getUrl() . '/delete')
425             ->press('Confirm')
426             ->seePageIs('/books')
427             ->dontSee($ownBook->name);
428     }
429
430     public function test_books_delete_all_permission()
431     {
432         $this->giveUserPermissions($this->user, ['book-update-all']);
433         $otherBook = Book::take(1)->get()->first();
434         $this->checkAccessPermission('book-delete-all', [
435             $otherBook->getUrl() . '/delete',
436         ], [
437             $otherBook->getUrl() => 'Delete',
438         ]);
439
440         $this->visit($otherBook->getUrl())->visit($otherBook->getUrl() . '/delete')
441             ->press('Confirm')
442             ->seePageIs('/books')
443             ->dontSee($otherBook->name);
444     }
445
446     public function test_chapter_create_own_permissions()
447     {
448         $book = Book::take(1)->get()->first();
449         $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
450         $this->checkAccessPermission('chapter-create-own', [
451             $ownBook->getUrl('/create-chapter'),
452         ], [
453             $ownBook->getUrl() => 'New Chapter',
454         ]);
455
456         $this->visit($ownBook->getUrl('/create-chapter'))
457             ->type('test chapter', 'name')
458             ->type('chapter desc', 'description')
459             ->press('Save Chapter')
460             ->seePageIs($ownBook->getUrl('/chapter/test-chapter'));
461
462         $this->visit($book->getUrl())
463             ->dontSeeInElement('.action-buttons', 'New Chapter')
464             ->visit($book->getUrl('/create-chapter'))
465             ->seePageIs('/');
466     }
467
468     public function test_chapter_create_all_permissions()
469     {
470         $book = Book::take(1)->get()->first();
471         $this->checkAccessPermission('chapter-create-all', [
472             $book->getUrl('/create-chapter'),
473         ], [
474             $book->getUrl() => 'New Chapter',
475         ]);
476
477         $this->visit($book->getUrl('/create-chapter'))
478             ->type('test chapter', 'name')
479             ->type('chapter desc', 'description')
480             ->press('Save Chapter')
481             ->seePageIs($book->getUrl('/chapter/test-chapter'));
482     }
483
484     public function test_chapter_edit_own_permission()
485     {
486         $otherChapter = Chapter::take(1)->get()->first();
487         $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
488         $this->checkAccessPermission('chapter-update-own', [
489             $ownChapter->getUrl() . '/edit',
490         ], [
491             $ownChapter->getUrl() => 'Edit',
492         ]);
493
494         $this->visit($otherChapter->getUrl())
495             ->dontSeeInElement('.action-buttons', 'Edit')
496             ->visit($otherChapter->getUrl() . '/edit')
497             ->seePageIs('/');
498     }
499
500     public function test_chapter_edit_all_permission()
501     {
502         $otherChapter = Chapter::take(1)->get()->first();
503         $this->checkAccessPermission('chapter-update-all', [
504             $otherChapter->getUrl() . '/edit',
505         ], [
506             $otherChapter->getUrl() => 'Edit',
507         ]);
508     }
509
510     public function test_chapter_delete_own_permission()
511     {
512         $this->giveUserPermissions($this->user, ['chapter-update-all']);
513         $otherChapter = Chapter::take(1)->get()->first();
514         $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
515         $this->checkAccessPermission('chapter-delete-own', [
516             $ownChapter->getUrl() . '/delete',
517         ], [
518             $ownChapter->getUrl() => 'Delete',
519         ]);
520
521         $bookUrl = $ownChapter->book->getUrl();
522         $this->visit($otherChapter->getUrl())
523             ->dontSeeInElement('.action-buttons', 'Delete')
524             ->visit($otherChapter->getUrl() . '/delete')
525             ->seePageIs('/');
526         $this->visit($ownChapter->getUrl())->visit($ownChapter->getUrl() . '/delete')
527             ->press('Confirm')
528             ->seePageIs($bookUrl)
529             ->dontSeeInElement('.book-content', $ownChapter->name);
530     }
531
532     public function test_chapter_delete_all_permission()
533     {
534         $this->giveUserPermissions($this->user, ['chapter-update-all']);
535         $otherChapter = Chapter::take(1)->get()->first();
536         $this->checkAccessPermission('chapter-delete-all', [
537             $otherChapter->getUrl() . '/delete',
538         ], [
539             $otherChapter->getUrl() => 'Delete',
540         ]);
541
542         $bookUrl = $otherChapter->book->getUrl();
543         $this->visit($otherChapter->getUrl())->visit($otherChapter->getUrl() . '/delete')
544             ->press('Confirm')
545             ->seePageIs($bookUrl)
546             ->dontSeeInElement('.book-content', $otherChapter->name);
547     }
548
549     public function test_page_create_own_permissions()
550     {
551         $book = Book::first();
552         $chapter = Chapter::first();
553
554         $entities = $this->createEntityChainBelongingToUser($this->user);
555         $ownBook = $entities['book'];
556         $ownChapter = $entities['chapter'];
557
558         $createUrl = $ownBook->getUrl('/create-page');
559         $createUrlChapter = $ownChapter->getUrl('/create-page');
560         $accessUrls = [$createUrl, $createUrlChapter];
561
562         foreach ($accessUrls as $url) {
563             $this->actingAs($this->user)->visit($url)
564                 ->seePageIs('/');
565         }
566
567         $this->checkAccessPermission('page-create-own', [], [
568             $ownBook->getUrl()    => 'New Page',
569             $ownChapter->getUrl() => 'New Page',
570         ]);
571
572         $this->giveUserPermissions($this->user, ['page-create-own']);
573
574         foreach ($accessUrls as $index => $url) {
575             $this->actingAs($this->user)->visit($url);
576             $expectedUrl = Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
577             $this->seePageIs($expectedUrl);
578         }
579
580         $this->visit($createUrl)
581             ->type('test page', 'name')
582             ->type('page desc', 'html')
583             ->press('Save Page')
584             ->seePageIs($ownBook->getUrl('/page/test-page'));
585
586         $this->visit($book->getUrl())
587             ->dontSeeInElement('.action-buttons', 'New Page')
588             ->visit($book->getUrl() . '/create-page')
589             ->seePageIs('/');
590         $this->visit($chapter->getUrl())
591             ->dontSeeInElement('.action-buttons', 'New Page')
592             ->visit($chapter->getUrl() . '/create-page')
593             ->seePageIs('/');
594     }
595
596     public function test_page_create_all_permissions()
597     {
598         $book = Book::take(1)->get()->first();
599         $chapter = Chapter::take(1)->get()->first();
600         $baseUrl = $book->getUrl() . '/page';
601         $createUrl = $book->getUrl('/create-page');
602
603         $createUrlChapter = $chapter->getUrl('/create-page');
604         $accessUrls = [$createUrl, $createUrlChapter];
605
606         foreach ($accessUrls as $url) {
607             $this->actingAs($this->user)->visit($url)
608                 ->seePageIs('/');
609         }
610
611         $this->checkAccessPermission('page-create-all', [], [
612             $book->getUrl()    => 'New Page',
613             $chapter->getUrl() => 'New Page',
614         ]);
615
616         $this->giveUserPermissions($this->user, ['page-create-all']);
617
618         foreach ($accessUrls as $index => $url) {
619             $this->actingAs($this->user)->visit($url);
620             $expectedUrl = Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
621             $this->seePageIs($expectedUrl);
622         }
623
624         $this->visit($createUrl)
625             ->type('test page', 'name')
626             ->type('page desc', 'html')
627             ->press('Save Page')
628             ->seePageIs($book->getUrl('/page/test-page'));
629
630         $this->visit($chapter->getUrl('/create-page'))
631             ->type('new test page', 'name')
632             ->type('page desc', 'html')
633             ->press('Save Page')
634             ->seePageIs($book->getUrl('/page/new-test-page'));
635     }
636
637     public function test_page_edit_own_permission()
638     {
639         $otherPage = Page::take(1)->get()->first();
640         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
641         $this->checkAccessPermission('page-update-own', [
642             $ownPage->getUrl() . '/edit',
643         ], [
644             $ownPage->getUrl() => 'Edit',
645         ]);
646
647         $this->visit($otherPage->getUrl())
648             ->dontSeeInElement('.action-buttons', 'Edit')
649             ->visit($otherPage->getUrl() . '/edit')
650             ->seePageIs('/');
651     }
652
653     public function test_page_edit_all_permission()
654     {
655         $otherPage = Page::take(1)->get()->first();
656         $this->checkAccessPermission('page-update-all', [
657             $otherPage->getUrl() . '/edit',
658         ], [
659             $otherPage->getUrl() => 'Edit',
660         ]);
661     }
662
663     public function test_page_delete_own_permission()
664     {
665         $this->giveUserPermissions($this->user, ['page-update-all']);
666         $otherPage = Page::take(1)->get()->first();
667         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
668         $this->checkAccessPermission('page-delete-own', [
669             $ownPage->getUrl() . '/delete',
670         ], [
671             $ownPage->getUrl() => 'Delete',
672         ]);
673
674         $parent = $ownPage->chapter ?? $ownPage->book;
675         $this->visit($otherPage->getUrl())
676             ->dontSeeInElement('.action-buttons', 'Delete')
677             ->visit($otherPage->getUrl() . '/delete')
678             ->seePageIs('/');
679         $this->visit($ownPage->getUrl())->visit($ownPage->getUrl() . '/delete')
680             ->press('Confirm')
681             ->seePageIs($parent->getUrl())
682             ->dontSeeInElement('.book-content', $ownPage->name);
683     }
684
685     public function test_page_delete_all_permission()
686     {
687         $this->giveUserPermissions($this->user, ['page-update-all']);
688         $otherPage = Page::take(1)->get()->first();
689         $this->checkAccessPermission('page-delete-all', [
690             $otherPage->getUrl() . '/delete',
691         ], [
692             $otherPage->getUrl() => 'Delete',
693         ]);
694
695         $parent = $otherPage->chapter ?? $otherPage->book;
696         $this->visit($otherPage->getUrl())->visit($otherPage->getUrl() . '/delete')
697             ->press('Confirm')
698             ->seePageIs($parent->getUrl())
699             ->dontSeeInElement('.book-content', $otherPage->name);
700     }
701
702     public function test_public_role_visible_in_user_edit_screen()
703     {
704         $user = User::first();
705         $adminRole = Role::getSystemRole('admin');
706         $publicRole = Role::getSystemRole('public');
707         $this->asAdmin()->visit('/settings/users/' . $user->id)
708             ->seeElement('[name="roles[' . $adminRole->id . ']"]')
709             ->seeElement('[name="roles[' . $publicRole->id . ']"]');
710     }
711
712     public function test_public_role_visible_in_role_listing()
713     {
714         $this->asAdmin()->visit('/settings/roles')
715             ->see('Admin')
716             ->see('Public');
717     }
718
719     public function test_public_role_visible_in_default_role_setting()
720     {
721         $this->asAdmin()->visit('/settings')
722             ->seeElement('[data-system-role-name="admin"]')
723             ->seeElement('[data-system-role-name="public"]');
724     }
725
726     public function test_public_role_not_deleteable()
727     {
728         $this->asAdmin()->visit('/settings/roles')
729             ->click('Public')
730             ->see('Edit Role')
731             ->click('Delete Role')
732             ->press('Confirm')
733             ->see('Delete Role')
734             ->see('Cannot be deleted');
735     }
736
737     public function test_image_delete_own_permission()
738     {
739         $this->giveUserPermissions($this->user, ['image-update-all']);
740         $page = Page::first();
741         $image = factory(Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $this->user->id, 'updated_by' => $this->user->id]);
742
743         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
744             ->seeStatusCode(403);
745
746         $this->giveUserPermissions($this->user, ['image-delete-own']);
747
748         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
749             ->seeStatusCode(200)
750             ->dontSeeInDatabase('images', ['id' => $image->id]);
751     }
752
753     public function test_image_delete_all_permission()
754     {
755         $this->giveUserPermissions($this->user, ['image-update-all']);
756         $admin = $this->getAdmin();
757         $page = Page::first();
758         $image = factory(Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $admin->id, 'updated_by' => $admin->id]);
759
760         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
761             ->seeStatusCode(403);
762
763         $this->giveUserPermissions($this->user, ['image-delete-own']);
764
765         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
766             ->seeStatusCode(403);
767
768         $this->giveUserPermissions($this->user, ['image-delete-all']);
769
770         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
771             ->seeStatusCode(200)
772             ->dontSeeInDatabase('images', ['id' => $image->id]);
773     }
774
775     public function test_role_permission_removal()
776     {
777         // To cover issue fixed in f99c8ff99aee9beb8c692f36d4b84dc6e651e50a.
778         $page = Page::first();
779         $viewerRole = Role::getRole('viewer');
780         $viewer = $this->getViewer();
781         $this->actingAs($viewer)->visit($page->getUrl())->assertResponseStatus(200);
782
783         $this->asAdmin()->put('/settings/roles/' . $viewerRole->id, [
784             'display_name' => $viewerRole->display_name,
785             'description'  => $viewerRole->description,
786             'permission'   => [],
787         ])->assertResponseStatus(302);
788
789         $this->expectException(HttpException::class);
790         $this->actingAs($viewer)->visit($page->getUrl())->assertResponseStatus(404);
791     }
792
793     public function test_empty_state_actions_not_visible_without_permission()
794     {
795         $admin = $this->getAdmin();
796         // Book links
797         $book = factory(Book::class)->create(['created_by' => $admin->id, 'updated_by' => $admin->id]);
798         $this->updateEntityPermissions($book);
799         $this->actingAs($this->getViewer())->visit($book->getUrl())
800             ->dontSee('Create a new page')
801             ->dontSee('Add a chapter');
802
803         // Chapter links
804         $chapter = factory(Chapter::class)->create(['created_by' => $admin->id, 'updated_by' => $admin->id, 'book_id' => $book->id]);
805         $this->updateEntityPermissions($chapter);
806         $this->actingAs($this->getViewer())->visit($chapter->getUrl())
807             ->dontSee('Create a new page')
808             ->dontSee('Sort the current book');
809     }
810
811     public function test_comment_create_permission()
812     {
813         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
814
815         $this->actingAs($this->user)->addComment($ownPage);
816
817         $this->assertResponseStatus(403);
818
819         $this->giveUserPermissions($this->user, ['comment-create-all']);
820
821         $this->actingAs($this->user)->addComment($ownPage);
822         $this->assertResponseStatus(200);
823     }
824
825     public function test_comment_update_own_permission()
826     {
827         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
828         $this->giveUserPermissions($this->user, ['comment-create-all']);
829         $commentId = $this->actingAs($this->user)->addComment($ownPage);
830
831         // no comment-update-own
832         $this->actingAs($this->user)->updateComment($commentId);
833         $this->assertResponseStatus(403);
834
835         $this->giveUserPermissions($this->user, ['comment-update-own']);
836
837         // now has comment-update-own
838         $this->actingAs($this->user)->updateComment($commentId);
839         $this->assertResponseStatus(200);
840     }
841
842     public function test_comment_update_all_permission()
843     {
844         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
845         $commentId = $this->asAdmin()->addComment($ownPage);
846
847         // no comment-update-all
848         $this->actingAs($this->user)->updateComment($commentId);
849         $this->assertResponseStatus(403);
850
851         $this->giveUserPermissions($this->user, ['comment-update-all']);
852
853         // now has comment-update-all
854         $this->actingAs($this->user)->updateComment($commentId);
855         $this->assertResponseStatus(200);
856     }
857
858     public function test_comment_delete_own_permission()
859     {
860         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
861         $this->giveUserPermissions($this->user, ['comment-create-all']);
862         $commentId = $this->actingAs($this->user)->addComment($ownPage);
863
864         // no comment-delete-own
865         $this->actingAs($this->user)->deleteComment($commentId);
866         $this->assertResponseStatus(403);
867
868         $this->giveUserPermissions($this->user, ['comment-delete-own']);
869
870         // now has comment-update-own
871         $this->actingAs($this->user)->deleteComment($commentId);
872         $this->assertResponseStatus(200);
873     }
874
875     public function test_comment_delete_all_permission()
876     {
877         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
878         $commentId = $this->asAdmin()->addComment($ownPage);
879
880         // no comment-delete-all
881         $this->actingAs($this->user)->deleteComment($commentId);
882         $this->assertResponseStatus(403);
883
884         $this->giveUserPermissions($this->user, ['comment-delete-all']);
885
886         // now has comment-delete-all
887         $this->actingAs($this->user)->deleteComment($commentId);
888         $this->assertResponseStatus(200);
889     }
890
891     private function addComment($page)
892     {
893         $comment = factory(Comment::class)->make();
894         $url = "/comment/$page->id";
895         $request = [
896             'text' => $comment->text,
897             'html' => $comment->html,
898         ];
899
900         $this->postJson($url, $request);
901         $comment = $page->comments()->first();
902
903         return $comment === null ? null : $comment->id;
904     }
905
906     private function updateComment($commentId)
907     {
908         $comment = factory(Comment::class)->make();
909         $url = "/comment/$commentId";
910         $request = [
911             'text' => $comment->text,
912             'html' => $comment->html,
913         ];
914
915         return $this->putJson($url, $request);
916     }
917
918     private function deleteComment($commentId)
919     {
920         $url = '/comment/' . $commentId;
921
922         return $this->json('DELETE', $url);
923     }
924 }