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