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