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