]> BookStack Code Mirror - bookstack/blob - tests/Permissions/RolePermissionsTest.php
Testing: Updated tests to account for recent page redirect changes
[bookstack] / tests / Permissions / RolePermissionsTest.php
1 <?php
2
3 namespace Tests\Permissions;
4
5 use BookStack\Activity\Models\Comment;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Bookshelf;
8 use BookStack\Entities\Models\Chapter;
9 use BookStack\Entities\Models\Entity;
10 use BookStack\Entities\Models\Page;
11 use BookStack\Uploads\Image;
12 use BookStack\Users\Models\User;
13 use Illuminate\Testing\TestResponse;
14 use Tests\TestCase;
15
16 class RolePermissionsTest extends TestCase
17 {
18     protected User $user;
19
20     protected function setUp(): void
21     {
22         parent::setUp();
23         $this->user = $this->users->viewer();
24     }
25
26     public function test_manage_user_permission()
27     {
28         $this->actingAs($this->user)->get('/settings/users')->assertRedirect('/');
29         $this->permissions->grantUserRolePermissions($this->user, ['users-manage']);
30         $this->actingAs($this->user)->get('/settings/users')->assertOk();
31     }
32
33     public function test_manage_users_permission_shows_link_in_header_if_does_not_have_settings_manage_permision()
34     {
35         $usersLink = 'href="' . url('/settings/users') . '"';
36         $this->actingAs($this->user)->get('/')->assertDontSee($usersLink, false);
37         $this->permissions->grantUserRolePermissions($this->user, ['users-manage']);
38         $this->actingAs($this->user)->get('/')->assertSee($usersLink, false);
39         $this->permissions->grantUserRolePermissions($this->user, ['settings-manage', 'users-manage']);
40         $this->actingAs($this->user)->get('/')->assertDontSee($usersLink, false);
41     }
42
43     public function test_user_cannot_change_email_unless_they_have_manage_users_permission()
44     {
45         $originalEmail = $this->user->email;
46         $this->actingAs($this->user);
47
48         $resp = $this->get('/my-account/profile')->assertOk();
49         $this->withHtml($resp)->assertElementExists('input[name=email][disabled]');
50         $resp->assertSee('Unfortunately you don\'t have permission to change your email address.');
51         $this->put('/my-account/profile', [
52             'name'  => 'my_new_name',
53             'email' => '[email protected]',
54         ]);
55         $this->assertDatabaseHas('users', [
56             'id'    => $this->user->id,
57             'email' => $originalEmail,
58             'name'  => 'my_new_name',
59         ]);
60
61         $this->permissions->grantUserRolePermissions($this->user, ['users-manage']);
62
63         $resp = $this->get('/my-account/profile')->assertOk();
64         $this->withHtml($resp)
65             ->assertElementNotExists('input[name=email][disabled]')
66             ->assertElementExists('input[name=email]');
67
68         $this->put('/my-account/profile', [
69             'name'  => 'my_new_name_2',
70             'email' => '[email protected]',
71         ]);
72
73         $this->assertDatabaseHas('users', [
74             'id'    => $this->user->id,
75             'email' => '[email protected]',
76             'name'  => 'my_new_name_2',
77         ]);
78     }
79
80     public function test_user_roles_manage_permission()
81     {
82         $this->actingAs($this->user)->get('/settings/roles')->assertRedirect('/');
83         $this->get('/settings/roles/1')->assertRedirect('/');
84         $this->permissions->grantUserRolePermissions($this->user, ['user-roles-manage']);
85         $this->actingAs($this->user)->get('/settings/roles')->assertOk();
86         $this->get('/settings/roles/1')
87             ->assertOk()
88             ->assertSee('Admin');
89     }
90
91     public function test_settings_manage_permission()
92     {
93         $this->actingAs($this->user)->get('/settings/features')->assertRedirect('/');
94         $this->permissions->grantUserRolePermissions($this->user, ['settings-manage']);
95         $this->get('/settings/features')->assertOk();
96
97         $resp = $this->post('/settings/features', []);
98         $resp->assertRedirect('/settings/features');
99         $resp = $this->get('/settings/features');
100         $resp->assertSee('Settings successfully updated');
101     }
102
103     public function test_restrictions_manage_all_permission()
104     {
105         $page = $this->entities->page();
106
107         $this->actingAs($this->user)->get($page->getUrl())->assertDontSee('Permissions');
108         $this->get($page->getUrl('/permissions'))->assertRedirect('/');
109
110         $this->permissions->grantUserRolePermissions($this->user, ['restrictions-manage-all']);
111
112         $this->actingAs($this->user)->get($page->getUrl())->assertSee('Permissions');
113
114         $this->get($page->getUrl('/permissions'))
115             ->assertOk()
116             ->assertSee('Page Permissions');
117     }
118
119     public function test_restrictions_manage_own_permission()
120     {
121         $otherUsersPage = $this->entities->page();
122         $content = $this->entities->createChainBelongingToUser($this->user);
123
124         // Set a different creator on the page we're checking to ensure
125         // that the owner fields are checked
126         $page = $content['page']; /** @var Page $page */
127         $page->created_by = $otherUsersPage->id;
128         $page->owned_by = $this->user->id;
129         $page->save();
130
131         // Check can't restrict other's content
132         $this->actingAs($this->user)->get($otherUsersPage->getUrl())->assertDontSee('Permissions');
133         $this->get($otherUsersPage->getUrl('/permissions'))->assertRedirect('/');
134
135         // Check can't restrict own content
136         $this->actingAs($this->user)->get($page->getUrl())->assertDontSee('Permissions');
137         $this->get($page->getUrl('/permissions'))->assertRedirect('/');
138
139         $this->permissions->grantUserRolePermissions($this->user, ['restrictions-manage-own']);
140
141         // Check can't restrict other's content
142         $this->actingAs($this->user)->get($otherUsersPage->getUrl())->assertDontSee('Permissions');
143         $this->get($otherUsersPage->getUrl('/permissions'))->assertRedirect();
144
145         // Check can restrict own content
146         $this->actingAs($this->user)->get($page->getUrl())->assertSee('Permissions');
147         $this->get($page->getUrl('/permissions'))->assertOk();
148     }
149
150     /**
151      * Check a standard entity access permission.
152      */
153     private function checkAccessPermission(
154         string $permission,
155         array $accessUrls = [],
156         array $visibles = [],
157         string $expectedRedirectUri = '/',
158     ) {
159         foreach ($accessUrls as $url) {
160             $this->actingAs($this->user)->get($url)->assertRedirect($expectedRedirectUri);
161         }
162
163         foreach ($visibles as $url => $text) {
164             $resp = $this->actingAs($this->user)->get($url);
165             $this->withHtml($resp)->assertElementNotContains('.action-buttons', $text);
166         }
167
168         $this->permissions->grantUserRolePermissions($this->user, [$permission]);
169
170         foreach ($accessUrls as $url) {
171             $this->actingAs($this->user)->get($url)->assertOk();
172         }
173         foreach ($visibles as $url => $text) {
174             $this->actingAs($this->user)->get($url)->assertSee($text);
175         }
176     }
177
178     public function test_bookshelves_create_all_permissions()
179     {
180         $this->checkAccessPermission('bookshelf-create-all', [
181             '/create-shelf',
182         ], [
183             '/shelves' => 'New Shelf',
184         ]);
185
186         $this->post('/shelves', [
187             'name'        => 'test shelf',
188             'description' => 'shelf desc',
189         ])->assertRedirect('/shelves/test-shelf');
190     }
191
192     public function test_bookshelves_edit_own_permission()
193     {
194         /** @var Bookshelf $otherShelf */
195         $otherShelf = Bookshelf::query()->first();
196         $ownShelf = $this->entities->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
197         $ownShelf->forceFill(['owned_by' => $this->user->id, 'updated_by' => $this->user->id])->save();
198         $this->permissions->regenerateForEntity($ownShelf);
199
200         $this->checkAccessPermission('bookshelf-update-own', [
201             $ownShelf->getUrl('/edit'),
202         ], [
203             $ownShelf->getUrl() => 'Edit',
204         ]);
205
206         $resp = $this->get($otherShelf->getUrl());
207         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
208         $this->get($otherShelf->getUrl('/edit'))->assertRedirect('/');
209     }
210
211     public function test_bookshelves_edit_all_permission()
212     {
213         /** @var Bookshelf $otherShelf */
214         $otherShelf = Bookshelf::query()->first();
215         $this->checkAccessPermission('bookshelf-update-all', [
216             $otherShelf->getUrl('/edit'),
217         ], [
218             $otherShelf->getUrl() => 'Edit',
219         ]);
220     }
221
222     public function test_bookshelves_delete_own_permission()
223     {
224         $this->permissions->grantUserRolePermissions($this->user, ['bookshelf-update-all']);
225         /** @var Bookshelf $otherShelf */
226         $otherShelf = Bookshelf::query()->first();
227         $ownShelf = $this->entities->newShelf(['name' => 'test-shelf', 'slug' => 'test-shelf']);
228         $ownShelf->forceFill(['owned_by' => $this->user->id, 'updated_by' => $this->user->id])->save();
229         $this->permissions->regenerateForEntity($ownShelf);
230
231         $this->checkAccessPermission('bookshelf-delete-own', [
232             $ownShelf->getUrl('/delete'),
233         ], [
234             $ownShelf->getUrl() => 'Delete',
235         ]);
236
237         $resp = $this->get($otherShelf->getUrl());
238         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
239         $this->get($otherShelf->getUrl('/delete'))->assertRedirect('/');
240
241         $this->get($ownShelf->getUrl());
242         $this->delete($ownShelf->getUrl())->assertRedirect('/shelves');
243         $this->get('/shelves')->assertDontSee($ownShelf->name);
244     }
245
246     public function test_bookshelves_delete_all_permission()
247     {
248         $this->permissions->grantUserRolePermissions($this->user, ['bookshelf-update-all']);
249         /** @var Bookshelf $otherShelf */
250         $otherShelf = Bookshelf::query()->first();
251         $this->checkAccessPermission('bookshelf-delete-all', [
252             $otherShelf->getUrl('/delete'),
253         ], [
254             $otherShelf->getUrl() => 'Delete',
255         ]);
256
257         $this->delete($otherShelf->getUrl())->assertRedirect('/shelves');
258         $this->get('/shelves')->assertDontSee($otherShelf->name);
259     }
260
261     public function test_books_create_all_permissions()
262     {
263         $this->checkAccessPermission('book-create-all', [
264             '/create-book',
265         ], [
266             '/books' => 'Create New Book',
267         ]);
268
269         $this->post('/books', [
270             'name'        => 'test book',
271             'description' => 'book desc',
272         ])->assertRedirect('/books/test-book');
273     }
274
275     public function test_books_edit_own_permission()
276     {
277         /** @var Book $otherBook */
278         $otherBook = Book::query()->take(1)->get()->first();
279         $ownBook = $this->entities->createChainBelongingToUser($this->user)['book'];
280         $this->checkAccessPermission('book-update-own', [
281             $ownBook->getUrl() . '/edit',
282         ], [
283             $ownBook->getUrl() => 'Edit',
284         ]);
285
286         $resp = $this->get($otherBook->getUrl());
287         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
288         $this->get($otherBook->getUrl('/edit'))->assertRedirect('/');
289     }
290
291     public function test_books_edit_all_permission()
292     {
293         /** @var Book $otherBook */
294         $otherBook = Book::query()->take(1)->get()->first();
295         $this->checkAccessPermission('book-update-all', [
296             $otherBook->getUrl() . '/edit',
297         ], [
298             $otherBook->getUrl() => 'Edit',
299         ]);
300     }
301
302     public function test_books_delete_own_permission()
303     {
304         $this->permissions->grantUserRolePermissions($this->user, ['book-update-all']);
305         /** @var Book $otherBook */
306         $otherBook = Book::query()->take(1)->get()->first();
307         $ownBook = $this->entities->createChainBelongingToUser($this->user)['book'];
308         $this->checkAccessPermission('book-delete-own', [
309             $ownBook->getUrl() . '/delete',
310         ], [
311             $ownBook->getUrl() => 'Delete',
312         ]);
313
314         $resp = $this->get($otherBook->getUrl());
315         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
316         $this->get($otherBook->getUrl('/delete'))->assertRedirect('/');
317         $this->get($ownBook->getUrl());
318         $this->delete($ownBook->getUrl())->assertRedirect('/books');
319         $this->get('/books')->assertDontSee($ownBook->name);
320     }
321
322     public function test_books_delete_all_permission()
323     {
324         $this->permissions->grantUserRolePermissions($this->user, ['book-update-all']);
325         /** @var Book $otherBook */
326         $otherBook = Book::query()->take(1)->get()->first();
327         $this->checkAccessPermission('book-delete-all', [
328             $otherBook->getUrl() . '/delete',
329         ], [
330             $otherBook->getUrl() => 'Delete',
331         ]);
332
333         $this->get($otherBook->getUrl());
334         $this->delete($otherBook->getUrl())->assertRedirect('/books');
335         $this->get('/books')->assertDontSee($otherBook->name);
336     }
337
338     public function test_chapter_create_own_permissions()
339     {
340         /** @var Book $book */
341         $book = Book::query()->take(1)->get()->first();
342         $ownBook = $this->entities->createChainBelongingToUser($this->user)['book'];
343         $this->checkAccessPermission('chapter-create-own', [
344             $ownBook->getUrl('/create-chapter'),
345         ], [
346             $ownBook->getUrl() => 'New Chapter',
347         ]);
348
349         $this->post($ownBook->getUrl('/create-chapter'), [
350             'name'        => 'test chapter',
351             'description' => 'chapter desc',
352         ])->assertRedirect($ownBook->getUrl('/chapter/test-chapter'));
353
354         $resp = $this->get($book->getUrl());
355         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'New Chapter');
356         $this->get($book->getUrl('/create-chapter'))->assertRedirect('/');
357     }
358
359     public function test_chapter_create_all_permissions()
360     {
361         $book = $this->entities->book();
362         $this->checkAccessPermission('chapter-create-all', [
363             $book->getUrl('/create-chapter'),
364         ], [
365             $book->getUrl() => 'New Chapter',
366         ]);
367
368         $this->post($book->getUrl('/create-chapter'), [
369             'name'        => 'test chapter',
370             'description' => 'chapter desc',
371         ])->assertRedirect($book->getUrl('/chapter/test-chapter'));
372     }
373
374     public function test_chapter_edit_own_permission()
375     {
376         /** @var Chapter $otherChapter */
377         $otherChapter = Chapter::query()->first();
378         $ownChapter = $this->entities->createChainBelongingToUser($this->user)['chapter'];
379         $this->checkAccessPermission('chapter-update-own', [
380             $ownChapter->getUrl() . '/edit',
381         ], [
382             $ownChapter->getUrl() => 'Edit',
383         ]);
384
385         $resp = $this->get($otherChapter->getUrl());
386         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
387         $this->get($otherChapter->getUrl('/edit'))->assertRedirect('/');
388     }
389
390     public function test_chapter_edit_all_permission()
391     {
392         /** @var Chapter $otherChapter */
393         $otherChapter = Chapter::query()->take(1)->get()->first();
394         $this->checkAccessPermission('chapter-update-all', [
395             $otherChapter->getUrl() . '/edit',
396         ], [
397             $otherChapter->getUrl() => 'Edit',
398         ]);
399     }
400
401     public function test_chapter_delete_own_permission()
402     {
403         $this->permissions->grantUserRolePermissions($this->user, ['chapter-update-all']);
404         /** @var Chapter $otherChapter */
405         $otherChapter = Chapter::query()->first();
406         $ownChapter = $this->entities->createChainBelongingToUser($this->user)['chapter'];
407         $this->checkAccessPermission('chapter-delete-own', [
408             $ownChapter->getUrl() . '/delete',
409         ], [
410             $ownChapter->getUrl() => 'Delete',
411         ]);
412
413         $bookUrl = $ownChapter->book->getUrl();
414         $resp = $this->get($otherChapter->getUrl());
415         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
416         $this->get($otherChapter->getUrl('/delete'))->assertRedirect('/');
417         $this->get($ownChapter->getUrl());
418         $this->delete($ownChapter->getUrl())->assertRedirect($bookUrl);
419         $resp = $this->get($bookUrl);
420         $this->withHtml($resp)->assertElementNotContains('.book-content', $ownChapter->name);
421     }
422
423     public function test_chapter_delete_all_permission()
424     {
425         $this->permissions->grantUserRolePermissions($this->user, ['chapter-update-all']);
426         /** @var Chapter $otherChapter */
427         $otherChapter = Chapter::query()->first();
428         $this->checkAccessPermission('chapter-delete-all', [
429             $otherChapter->getUrl() . '/delete',
430         ], [
431             $otherChapter->getUrl() => 'Delete',
432         ]);
433
434         $bookUrl = $otherChapter->book->getUrl();
435         $this->get($otherChapter->getUrl());
436         $this->delete($otherChapter->getUrl())->assertRedirect($bookUrl);
437         $resp = $this->get($bookUrl);
438         $this->withHtml($resp)->assertElementNotContains('.book-content', $otherChapter->name);
439     }
440
441     public function test_page_create_own_permissions()
442     {
443         $book = $this->entities->book();
444         $chapter = $this->entities->chapter();
445
446         $entities = $this->entities->createChainBelongingToUser($this->user);
447         $ownBook = $entities['book'];
448         $ownChapter = $entities['chapter'];
449
450         $createUrl = $ownBook->getUrl('/create-page');
451         $createUrlChapter = $ownChapter->getUrl('/create-page');
452         $accessUrls = [$createUrl, $createUrlChapter];
453
454         foreach ($accessUrls as $url) {
455             $this->actingAs($this->user)->get($url)->assertRedirect('/');
456         }
457
458         $this->checkAccessPermission('page-create-own', [], [
459             $ownBook->getUrl()    => 'New Page',
460             $ownChapter->getUrl() => 'New Page',
461         ]);
462
463         $this->permissions->grantUserRolePermissions($this->user, ['page-create-own']);
464
465         foreach ($accessUrls as $index => $url) {
466             $resp = $this->actingAs($this->user)->get($url);
467             $expectedUrl = Page::query()->where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
468             $resp->assertRedirect($expectedUrl);
469         }
470
471         $this->get($createUrl);
472         /** @var Page $draft */
473         $draft = Page::query()->where('draft', '=', true)->orderBy('id', 'desc')->first();
474         $this->post($draft->getUrl(), [
475             'name' => 'test page',
476             'html' => 'page desc',
477         ])->assertRedirect($ownBook->getUrl('/page/test-page'));
478
479         $resp = $this->get($book->getUrl());
480         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'New Page');
481         $this->get($book->getUrl('/create-page'))->assertRedirect('/');
482
483         $resp = $this->get($chapter->getUrl());
484         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'New Page');
485         $this->get($chapter->getUrl('/create-page'))->assertRedirect('/');
486     }
487
488     public function test_page_create_all_permissions()
489     {
490         $book = $this->entities->book();
491         $chapter = $this->entities->chapter();
492         $createUrl = $book->getUrl('/create-page');
493
494         $createUrlChapter = $chapter->getUrl('/create-page');
495         $accessUrls = [$createUrl, $createUrlChapter];
496
497         foreach ($accessUrls as $url) {
498             $this->actingAs($this->user)->get($url)->assertRedirect('/');
499         }
500
501         $this->checkAccessPermission('page-create-all', [], [
502             $book->getUrl()    => 'New Page',
503             $chapter->getUrl() => 'New Page',
504         ]);
505
506         $this->permissions->grantUserRolePermissions($this->user, ['page-create-all']);
507
508         foreach ($accessUrls as $index => $url) {
509             $resp = $this->actingAs($this->user)->get($url);
510             $expectedUrl = Page::query()->where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
511             $resp->assertRedirect($expectedUrl);
512         }
513
514         $this->get($createUrl);
515         /** @var Page $draft */
516         $draft = Page::query()->where('draft', '=', true)->orderByDesc('id')->first();
517         $this->post($draft->getUrl(), [
518             'name' => 'test page',
519             'html' => 'page desc',
520         ])->assertRedirect($book->getUrl('/page/test-page'));
521
522         $this->get($chapter->getUrl('/create-page'));
523         /** @var Page $draft */
524         $draft = Page::query()->where('draft', '=', true)->orderByDesc('id')->first();
525         $this->post($draft->getUrl(), [
526             'name' => 'new test page',
527             'html' => 'page desc',
528         ])->assertRedirect($book->getUrl('/page/new-test-page'));
529     }
530
531     public function test_page_edit_own_permission()
532     {
533         /** @var Page $otherPage */
534         $otherPage = Page::query()->first();
535         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
536         $this->checkAccessPermission('page-update-own', [
537             $ownPage->getUrl() . '/edit',
538         ], [
539             $ownPage->getUrl() => 'Edit',
540         ], $ownPage->getUrl());
541
542         $resp = $this->get($otherPage->getUrl());
543         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Edit');
544         $this->get($otherPage->getUrl() . '/edit')->assertRedirect($otherPage->getUrl());
545     }
546
547     public function test_page_edit_all_permission()
548     {
549         /** @var Page $otherPage */
550         $otherPage = Page::query()->first();
551         $this->checkAccessPermission('page-update-all', [
552             $otherPage->getUrl('/edit'),
553         ], [
554             $otherPage->getUrl() => 'Edit',
555         ], $otherPage->getUrl());
556     }
557
558     public function test_page_delete_own_permission()
559     {
560         $this->permissions->grantUserRolePermissions($this->user, ['page-update-all']);
561         /** @var Page $otherPage */
562         $otherPage = Page::query()->first();
563         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
564         $this->checkAccessPermission('page-delete-own', [
565             $ownPage->getUrl() . '/delete',
566         ], [
567             $ownPage->getUrl() => 'Delete',
568         ]);
569
570         $parent = $ownPage->chapter ?? $ownPage->book;
571         $resp = $this->get($otherPage->getUrl());
572         $this->withHtml($resp)->assertElementNotContains('.action-buttons', 'Delete');
573         $this->get($otherPage->getUrl('/delete'))->assertRedirect('/');
574         $this->get($ownPage->getUrl());
575         $this->delete($ownPage->getUrl())->assertRedirect($parent->getUrl());
576         $resp = $this->get($parent->getUrl());
577         $this->withHtml($resp)->assertElementNotContains('.book-content', $ownPage->name);
578     }
579
580     public function test_page_delete_all_permission()
581     {
582         $this->permissions->grantUserRolePermissions($this->user, ['page-update-all']);
583         /** @var Page $otherPage */
584         $otherPage = Page::query()->first();
585
586         $this->checkAccessPermission('page-delete-all', [
587             $otherPage->getUrl() . '/delete',
588         ], [
589             $otherPage->getUrl() => 'Delete',
590         ]);
591
592         /** @var Entity $parent */
593         $parent = $otherPage->chapter ?? $otherPage->book;
594         $this->get($otherPage->getUrl());
595
596         $this->delete($otherPage->getUrl())->assertRedirect($parent->getUrl());
597         $this->get($parent->getUrl())->assertDontSee($otherPage->name);
598     }
599
600
601     public function test_image_delete_own_permission()
602     {
603         $this->permissions->grantUserRolePermissions($this->user, ['image-update-all']);
604         $page = $this->entities->page();
605         $image = Image::factory()->create([
606             'uploaded_to' => $page->id,
607             'created_by'  => $this->user->id,
608             'updated_by'  => $this->user->id,
609         ]);
610
611         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)->assertStatus(403);
612
613         $this->permissions->grantUserRolePermissions($this->user, ['image-delete-own']);
614
615         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)->assertOk();
616         $this->assertDatabaseMissing('images', ['id' => $image->id]);
617     }
618
619     public function test_image_delete_all_permission()
620     {
621         $this->permissions->grantUserRolePermissions($this->user, ['image-update-all']);
622         $admin = $this->users->admin();
623         $page = $this->entities->page();
624         $image = Image::factory()->create(['uploaded_to' => $page->id, 'created_by' => $admin->id, 'updated_by' => $admin->id]);
625
626         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)->assertStatus(403);
627
628         $this->permissions->grantUserRolePermissions($this->user, ['image-delete-own']);
629
630         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)->assertStatus(403);
631
632         $this->permissions->grantUserRolePermissions($this->user, ['image-delete-all']);
633
634         $this->actingAs($this->user)->json('delete', '/images/' . $image->id)->assertOk();
635         $this->assertDatabaseMissing('images', ['id' => $image->id]);
636     }
637
638     public function test_empty_state_actions_not_visible_without_permission()
639     {
640         $admin = $this->users->admin();
641         // Book links
642         $book = Book::factory()->create(['created_by' => $admin->id, 'updated_by' => $admin->id]);
643         $this->permissions->regenerateForEntity($book);
644         $this->actingAs($this->users->viewer())->get($book->getUrl())
645             ->assertDontSee('Create a new page')
646             ->assertDontSee('Add a chapter');
647
648         // Chapter links
649         $chapter = Chapter::factory()->create(['created_by' => $admin->id, 'updated_by' => $admin->id, 'book_id' => $book->id]);
650         $this->permissions->regenerateForEntity($chapter);
651         $this->actingAs($this->users->viewer())->get($chapter->getUrl())
652             ->assertDontSee('Create a new page')
653             ->assertDontSee('Sort the current book');
654     }
655
656     public function test_comment_create_permission()
657     {
658         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
659
660         $this->actingAs($this->user)
661             ->addComment($ownPage)
662             ->assertStatus(403);
663
664         $this->permissions->grantUserRolePermissions($this->user, ['comment-create-all']);
665
666         $this->actingAs($this->user)
667             ->addComment($ownPage)
668             ->assertOk();
669     }
670
671     public function test_comment_update_own_permission()
672     {
673         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
674         $this->permissions->grantUserRolePermissions($this->user, ['comment-create-all']);
675         $this->actingAs($this->user)->addComment($ownPage);
676         /** @var Comment $comment */
677         $comment = $ownPage->comments()->latest()->first();
678
679         // no comment-update-own
680         $this->actingAs($this->user)->updateComment($comment)->assertStatus(403);
681
682         $this->permissions->grantUserRolePermissions($this->user, ['comment-update-own']);
683
684         // now has comment-update-own
685         $this->actingAs($this->user)->updateComment($comment)->assertOk();
686     }
687
688     public function test_comment_update_all_permission()
689     {
690         /** @var Page $ownPage */
691         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
692         $this->asAdmin()->addComment($ownPage);
693         /** @var Comment $comment */
694         $comment = $ownPage->comments()->latest()->first();
695
696         // no comment-update-all
697         $this->actingAs($this->user)->updateComment($comment)->assertStatus(403);
698
699         $this->permissions->grantUserRolePermissions($this->user, ['comment-update-all']);
700
701         // now has comment-update-all
702         $this->actingAs($this->user)->updateComment($comment)->assertOk();
703     }
704
705     public function test_comment_delete_own_permission()
706     {
707         /** @var Page $ownPage */
708         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
709         $this->permissions->grantUserRolePermissions($this->user, ['comment-create-all']);
710         $this->actingAs($this->user)->addComment($ownPage);
711
712         /** @var Comment $comment */
713         $comment = $ownPage->comments()->latest()->first();
714
715         // no comment-delete-own
716         $this->actingAs($this->user)->deleteComment($comment)->assertStatus(403);
717
718         $this->permissions->grantUserRolePermissions($this->user, ['comment-delete-own']);
719
720         // now has comment-update-own
721         $this->actingAs($this->user)->deleteComment($comment)->assertOk();
722     }
723
724     public function test_comment_delete_all_permission()
725     {
726         /** @var Page $ownPage */
727         $ownPage = $this->entities->createChainBelongingToUser($this->user)['page'];
728         $this->asAdmin()->addComment($ownPage);
729         /** @var Comment $comment */
730         $comment = $ownPage->comments()->latest()->first();
731
732         // no comment-delete-all
733         $this->actingAs($this->user)->deleteComment($comment)->assertStatus(403);
734
735         $this->permissions->grantUserRolePermissions($this->user, ['comment-delete-all']);
736
737         // now has comment-delete-all
738         $this->actingAs($this->user)->deleteComment($comment)->assertOk();
739     }
740
741     private function addComment(Page $page): TestResponse
742     {
743         return $this->postJson("/comment/$page->id", ['html' => '<p>New comment content</p>']);
744     }
745
746     private function updateComment(Comment $comment): TestResponse
747     {
748         return $this->putJson("/comment/{$comment->id}", ['html' => '<p>Updated comment content</p>']);
749     }
750
751     private function deleteComment(Comment $comment): TestResponse
752     {
753         return $this->json('DELETE', '/comment/' . $comment->id);
754     }
755 }