]> BookStack Code Mirror - bookstack/blob - tests/Permissions/RolesTest.php
Added hidden public role to fit with new permissions system
[bookstack] / tests / Permissions / RolesTest.php
1 <?php
2
3 class RolesTest extends TestCase
4 {
5     protected $user;
6
7     public function setUp()
8     {
9         parent::setUp();
10         $this->user = $this->getViewer();
11     }
12
13     protected function getViewer()
14     {
15         $role = \BookStack\Role::getRole('viewer');
16         $viewer = $this->getNewBlankUser();
17         $viewer->attachRole($role);;
18         return $viewer;
19     }
20
21     /**
22      * Give the given user some permissions.
23      * @param \BookStack\User $user
24      * @param array $permissions
25      */
26     protected function giveUserPermissions(\BookStack\User $user, $permissions = [])
27     {
28         $newRole = $this->createNewRole($permissions);
29         $user->attachRole($newRole);
30         $user->load('roles');
31         $user->permissions(false);
32     }
33
34     /**
35      * Create a new basic role for testing purposes.
36      * @param array $permissions
37      * @return static
38      */
39     protected function createNewRole($permissions = [])
40     {
41         $permissionRepo = app('BookStack\Repos\PermissionsRepo');
42         $roleData = factory(\BookStack\Role::class)->make()->toArray();
43         $roleData['permissions'] = array_flip($permissions);
44         return $permissionRepo->saveNewRole($roleData);
45     }
46
47     public function test_admin_can_see_settings()
48     {
49         $this->asAdmin()->visit('/settings')->see('Settings');
50     }
51
52     public function test_cannot_delete_admin_role()
53     {
54         $adminRole = \BookStack\Role::getRole('admin');
55         $deletePageUrl = '/settings/roles/delete/' . $adminRole->id;
56         $this->asAdmin()->visit($deletePageUrl)
57             ->press('Confirm')
58             ->seePageIs($deletePageUrl)
59             ->see('cannot be deleted');
60     }
61
62     public function test_role_cannot_be_deleted_if_default()
63     {
64         $newRole = $this->createNewRole();
65         $this->setSettings(['registration-role' => $newRole->id]);
66
67         $deletePageUrl = '/settings/roles/delete/' . $newRole->id;
68         $this->asAdmin()->visit($deletePageUrl)
69             ->press('Confirm')
70             ->seePageIs($deletePageUrl)
71             ->see('cannot be deleted');
72     }
73
74     public function test_role_create_update_delete_flow()
75     {
76         $testRoleName = 'Test Role';
77         $testRoleDesc = 'a little test description';
78         $testRoleUpdateName = 'An Super Updated role';
79
80         // Creation
81         $this->asAdmin()->visit('/settings')
82             ->click('Roles')
83             ->seePageIs('/settings/roles')
84             ->click('Add new role')
85             ->type('Test Role', 'display_name')
86             ->type('A little test description', 'description')
87             ->press('Save Role')
88             ->seeInDatabase('roles', ['display_name' => $testRoleName, 'name' => 'test-role', 'description' => $testRoleDesc])
89             ->seePageIs('/settings/roles');
90         // Updating
91         $this->asAdmin()->visit('/settings/roles')
92             ->see($testRoleDesc)
93             ->click($testRoleName)
94             ->type($testRoleUpdateName, '#display_name')
95             ->press('Save Role')
96             ->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'name' => 'test-role', 'description' => $testRoleDesc])
97             ->seePageIs('/settings/roles');
98         // Deleting
99         $this->asAdmin()->visit('/settings/roles')
100             ->click($testRoleUpdateName)
101             ->click('Delete Role')
102             ->see($testRoleUpdateName)
103             ->press('Confirm')
104             ->seePageIs('/settings/roles')
105             ->dontSee($testRoleUpdateName);
106     }
107
108     public function test_manage_user_permission()
109     {
110         $this->actingAs($this->user)->visit('/')->visit('/settings/users')
111             ->seePageIs('/');
112         $this->giveUserPermissions($this->user, ['users-manage']);
113         $this->actingAs($this->user)->visit('/')->visit('/settings/users')
114             ->seePageIs('/settings/users');
115     }
116
117     public function test_user_roles_manage_permission()
118     {
119         $this->actingAs($this->user)->visit('/')->visit('/settings/roles')
120             ->seePageIs('/')->visit('/settings/roles/1')->seePageIs('/');
121         $this->giveUserPermissions($this->user, ['user-roles-manage']);
122         $this->actingAs($this->user)->visit('/settings/roles')
123             ->seePageIs('/settings/roles')->click('Admin')
124             ->see('Edit Role');
125     }
126
127     public function test_settings_manage_permission()
128     {
129         $this->actingAs($this->user)->visit('/')->visit('/settings')
130             ->seePageIs('/');
131         $this->giveUserPermissions($this->user, ['settings-manage']);
132         $this->actingAs($this->user)->visit('/')->visit('/settings')
133             ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved');
134     }
135
136     public function test_restrictions_manage_all_permission()
137     {
138         $page = \BookStack\Page::take(1)->get()->first();
139         $this->actingAs($this->user)->visit($page->getUrl())
140             ->dontSee('Permissions')
141             ->visit($page->getUrl() . '/permissions')
142             ->seePageIs('/');
143         $this->giveUserPermissions($this->user, ['restrictions-manage-all']);
144         $this->actingAs($this->user)->visit($page->getUrl())
145             ->see('Permissions')
146             ->click('Permissions')
147             ->see('Page Permissions')->seePageIs($page->getUrl() . '/permissions');
148     }
149
150     public function test_restrictions_manage_own_permission()
151     {
152         $otherUsersPage = \BookStack\Page::first();
153         $content = $this->createEntityChainBelongingToUser($this->user);
154         // Check can't restrict other's content
155         $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
156             ->dontSee('Permissions')
157             ->visit($otherUsersPage->getUrl() . '/permissions')
158             ->seePageIs('/');
159         // Check can't restrict own content
160         $this->actingAs($this->user)->visit($content['page']->getUrl())
161             ->dontSee('Permissions')
162             ->visit($content['page']->getUrl() . '/permissions')
163             ->seePageIs('/');
164
165         $this->giveUserPermissions($this->user, ['restrictions-manage-own']);
166
167         // Check can't restrict other's content
168         $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
169             ->dontSee('Permissions')
170             ->visit($otherUsersPage->getUrl() . '/permissions')
171             ->seePageIs('/');
172         // Check can restrict own content
173         $this->actingAs($this->user)->visit($content['page']->getUrl())
174             ->see('Permissions')
175             ->click('Permissions')
176             ->seePageIs($content['page']->getUrl() . '/permissions');
177     }
178
179     /**
180      * Check a standard entity access permission
181      * @param string $permission
182      * @param array $accessUrls Urls that are only accessible after having the permission
183      * @param array $visibles Check this text, In the buttons toolbar, is only visible with the permission
184      * @param null $callback
185      */
186     private function checkAccessPermission($permission, $accessUrls = [], $visibles = [])
187     {
188         foreach ($accessUrls as $url) {
189             $this->actingAs($this->user)->visit('/')->visit($url)
190                 ->seePageIs('/');
191         }
192         foreach ($visibles as $url => $text) {
193             $this->actingAs($this->user)->visit('/')->visit($url)
194                 ->dontSeeInElement('.action-buttons',$text);
195         }
196
197         $this->giveUserPermissions($this->user, [$permission]);
198
199         foreach ($accessUrls as $url) {
200             $this->actingAs($this->user)->visit('/')->visit($url)
201                 ->seePageIs($url);
202         }
203         foreach ($visibles as $url => $text) {
204             $this->actingAs($this->user)->visit('/')->visit($url)
205                 ->see($text);
206         }
207     }
208
209     public function test_books_create_all_permissions()
210     {
211         $this->checkAccessPermission('book-create-all', [
212             '/books/create'
213         ], [
214             '/books' => 'Add new book'
215         ]);
216
217         $this->visit('/books/create')
218             ->type('test book', 'name')
219             ->type('book desc', 'description')
220             ->press('Save Book')
221             ->seePageIs('/books/test-book');
222     }
223
224     public function test_books_edit_own_permission()
225     {
226         $otherBook = \BookStack\Book::take(1)->get()->first();
227         $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
228         $this->checkAccessPermission('book-update-own', [
229             $ownBook->getUrl() . '/edit'
230         ], [
231             $ownBook->getUrl() => 'Edit'
232         ]);
233
234         $this->visit($otherBook->getUrl())
235             ->dontSeeInElement('.action-buttons', 'Edit')
236             ->visit($otherBook->getUrl() . '/edit')
237             ->seePageIs('/');
238     }
239
240     public function test_books_edit_all_permission()
241     {
242         $otherBook = \BookStack\Book::take(1)->get()->first();
243         $this->checkAccessPermission('book-update-all', [
244             $otherBook->getUrl() . '/edit'
245         ], [
246             $otherBook->getUrl() => 'Edit'
247         ]);
248     }
249
250     public function test_books_delete_own_permission()
251     {
252         $this->giveUserPermissions($this->user, ['book-update-all']);
253         $otherBook = \BookStack\Book::take(1)->get()->first();
254         $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
255         $this->checkAccessPermission('book-delete-own', [
256             $ownBook->getUrl() . '/delete'
257         ], [
258             $ownBook->getUrl() => 'Delete'
259         ]);
260
261         $this->visit($otherBook->getUrl())
262             ->dontSeeInElement('.action-buttons', 'Delete')
263             ->visit($otherBook->getUrl() . '/delete')
264             ->seePageIs('/');
265         $this->visit($ownBook->getUrl())->visit($ownBook->getUrl() . '/delete')
266             ->press('Confirm')
267             ->seePageIs('/books')
268             ->dontSee($ownBook->name);
269     }
270
271     public function test_books_delete_all_permission()
272     {
273         $this->giveUserPermissions($this->user, ['book-update-all']);
274         $otherBook = \BookStack\Book::take(1)->get()->first();
275         $this->checkAccessPermission('book-delete-all', [
276             $otherBook->getUrl() . '/delete'
277         ], [
278             $otherBook->getUrl() => 'Delete'
279         ]);
280
281         $this->visit($otherBook->getUrl())->visit($otherBook->getUrl() . '/delete')
282             ->press('Confirm')
283             ->seePageIs('/books')
284             ->dontSee($otherBook->name);
285     }
286
287     public function test_chapter_create_own_permissions()
288     {
289         $book = \BookStack\Book::take(1)->get()->first();
290         $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
291         $baseUrl = $ownBook->getUrl() . '/chapter';
292         $this->checkAccessPermission('chapter-create-own', [
293             $baseUrl . '/create'
294         ], [
295             $ownBook->getUrl() => 'New Chapter'
296         ]);
297
298         $this->visit($baseUrl . '/create')
299             ->type('test chapter', 'name')
300             ->type('chapter desc', 'description')
301             ->press('Save Chapter')
302             ->seePageIs($baseUrl . '/test-chapter');
303
304         $this->visit($book->getUrl())
305             ->dontSeeInElement('.action-buttons', 'New Chapter')
306             ->visit($book->getUrl() . '/chapter/create')
307             ->seePageIs('/');
308     }
309
310     public function test_chapter_create_all_permissions()
311     {
312         $book = \BookStack\Book::take(1)->get()->first();
313         $baseUrl = $book->getUrl() . '/chapter';
314         $this->checkAccessPermission('chapter-create-all', [
315             $baseUrl . '/create'
316         ], [
317             $book->getUrl() => 'New Chapter'
318         ]);
319
320         $this->visit($baseUrl . '/create')
321             ->type('test chapter', 'name')
322             ->type('chapter desc', 'description')
323             ->press('Save Chapter')
324             ->seePageIs($baseUrl . '/test-chapter');
325     }
326
327     public function test_chapter_edit_own_permission()
328     {
329         $otherChapter = \BookStack\Chapter::take(1)->get()->first();
330         $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
331         $this->checkAccessPermission('chapter-update-own', [
332             $ownChapter->getUrl() . '/edit'
333         ], [
334             $ownChapter->getUrl() => 'Edit'
335         ]);
336
337         $this->visit($otherChapter->getUrl())
338             ->dontSeeInElement('.action-buttons', 'Edit')
339             ->visit($otherChapter->getUrl() . '/edit')
340             ->seePageIs('/');
341     }
342
343     public function test_chapter_edit_all_permission()
344     {
345         $otherChapter = \BookStack\Chapter::take(1)->get()->first();
346         $this->checkAccessPermission('chapter-update-all', [
347             $otherChapter->getUrl() . '/edit'
348         ], [
349             $otherChapter->getUrl() => 'Edit'
350         ]);
351     }
352
353     public function test_chapter_delete_own_permission()
354     {
355         $this->giveUserPermissions($this->user, ['chapter-update-all']);
356         $otherChapter = \BookStack\Chapter::take(1)->get()->first();
357         $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
358         $this->checkAccessPermission('chapter-delete-own', [
359             $ownChapter->getUrl() . '/delete'
360         ], [
361             $ownChapter->getUrl() => 'Delete'
362         ]);
363
364         $bookUrl = $ownChapter->book->getUrl();
365         $this->visit($otherChapter->getUrl())
366             ->dontSeeInElement('.action-buttons', 'Delete')
367             ->visit($otherChapter->getUrl() . '/delete')
368             ->seePageIs('/');
369         $this->visit($ownChapter->getUrl())->visit($ownChapter->getUrl() . '/delete')
370             ->press('Confirm')
371             ->seePageIs($bookUrl)
372             ->dontSeeInElement('.book-content', $ownChapter->name);
373     }
374
375     public function test_chapter_delete_all_permission()
376     {
377         $this->giveUserPermissions($this->user, ['chapter-update-all']);
378         $otherChapter = \BookStack\Chapter::take(1)->get()->first();
379         $this->checkAccessPermission('chapter-delete-all', [
380             $otherChapter->getUrl() . '/delete'
381         ], [
382             $otherChapter->getUrl() => 'Delete'
383         ]);
384
385         $bookUrl = $otherChapter->book->getUrl();
386         $this->visit($otherChapter->getUrl())->visit($otherChapter->getUrl() . '/delete')
387             ->press('Confirm')
388             ->seePageIs($bookUrl)
389             ->dontSeeInElement('.book-content', $otherChapter->name);
390     }
391
392     public function test_page_create_own_permissions()
393     {
394         $book = \BookStack\Book::take(1)->get()->first();
395         $chapter = \BookStack\Chapter::take(1)->get()->first();
396
397         $entities = $this->createEntityChainBelongingToUser($this->user);
398         $ownBook = $entities['book'];
399         $ownChapter = $entities['chapter'];
400
401         $baseUrl = $ownBook->getUrl() . '/page';
402
403         $createUrl = $baseUrl . '/create';
404         $createUrlChapter = $ownChapter->getUrl() . '/create-page';
405         $accessUrls = [$createUrl, $createUrlChapter];
406
407         foreach ($accessUrls as $url) {
408             $this->actingAs($this->user)->visit('/')->visit($url)
409                 ->seePageIs('/');
410         }
411
412         $this->checkAccessPermission('page-create-own', [], [
413             $ownBook->getUrl() => 'New Page',
414             $ownChapter->getUrl() => 'New Page'
415         ]);
416
417         $this->giveUserPermissions($this->user, ['page-create-own']);
418
419         foreach ($accessUrls as $index => $url) {
420             $this->actingAs($this->user)->visit('/')->visit($url);
421             $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
422             $this->seePageIs($expectedUrl);
423         }
424
425         $this->visit($baseUrl . '/create')
426             ->type('test page', 'name')
427             ->type('page desc', 'html')
428             ->press('Save Page')
429             ->seePageIs($baseUrl . '/test-page');
430
431         $this->visit($book->getUrl())
432             ->dontSeeInElement('.action-buttons', 'New Page')
433             ->visit($book->getUrl() . '/page/create')
434             ->seePageIs('/');
435         $this->visit($chapter->getUrl())
436             ->dontSeeInElement('.action-buttons', 'New Page')
437             ->visit($chapter->getUrl() . '/create-page')
438             ->seePageIs('/');
439     }
440
441     public function test_page_create_all_permissions()
442     {
443         $book = \BookStack\Book::take(1)->get()->first();
444         $chapter = \BookStack\Chapter::take(1)->get()->first();
445         $baseUrl = $book->getUrl() . '/page';
446         $createUrl = $baseUrl . '/create';
447
448         $createUrlChapter = $chapter->getUrl() . '/create-page';
449         $accessUrls = [$createUrl, $createUrlChapter];
450
451         foreach ($accessUrls as $url) {
452             $this->actingAs($this->user)->visit('/')->visit($url)
453                 ->seePageIs('/');
454         }
455
456         $this->checkAccessPermission('page-create-all', [], [
457             $book->getUrl() => 'New Page',
458             $chapter->getUrl() => 'New Page'
459         ]);
460
461         $this->giveUserPermissions($this->user, ['page-create-all']);
462
463         foreach ($accessUrls as $index => $url) {
464             $this->actingAs($this->user)->visit('/')->visit($url);
465             $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
466             $this->seePageIs($expectedUrl);
467         }
468
469         $this->visit($baseUrl . '/create')
470             ->type('test page', 'name')
471             ->type('page desc', 'html')
472             ->press('Save Page')
473             ->seePageIs($baseUrl . '/test-page');
474
475         $this->visit($chapter->getUrl() . '/create-page')
476             ->type('new test page', 'name')
477             ->type('page desc', 'html')
478             ->press('Save Page')
479             ->seePageIs($baseUrl . '/new-test-page');
480     }
481
482     public function test_page_edit_own_permission()
483     {
484         $otherPage = \BookStack\Page::take(1)->get()->first();
485         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
486         $this->checkAccessPermission('page-update-own', [
487             $ownPage->getUrl() . '/edit'
488         ], [
489             $ownPage->getUrl() => 'Edit'
490         ]);
491
492         $this->visit($otherPage->getUrl())
493             ->dontSeeInElement('.action-buttons', 'Edit')
494             ->visit($otherPage->getUrl() . '/edit')
495             ->seePageIs('/');
496     }
497
498     public function test_page_edit_all_permission()
499     {
500         $otherPage = \BookStack\Page::take(1)->get()->first();
501         $this->checkAccessPermission('page-update-all', [
502             $otherPage->getUrl() . '/edit'
503         ], [
504             $otherPage->getUrl() => 'Edit'
505         ]);
506     }
507
508     public function test_page_delete_own_permission()
509     {
510         $this->giveUserPermissions($this->user, ['page-update-all']);
511         $otherPage = \BookStack\Page::take(1)->get()->first();
512         $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
513         $this->checkAccessPermission('page-delete-own', [
514             $ownPage->getUrl() . '/delete'
515         ], [
516             $ownPage->getUrl() => 'Delete'
517         ]);
518
519         $bookUrl = $ownPage->book->getUrl();
520         $this->visit($otherPage->getUrl())
521             ->dontSeeInElement('.action-buttons', 'Delete')
522             ->visit($otherPage->getUrl() . '/delete')
523             ->seePageIs('/');
524         $this->visit($ownPage->getUrl())->visit($ownPage->getUrl() . '/delete')
525             ->press('Confirm')
526             ->seePageIs($bookUrl)
527             ->dontSeeInElement('.book-content', $ownPage->name);
528     }
529
530     public function test_page_delete_all_permission()
531     {
532         $this->giveUserPermissions($this->user, ['page-update-all']);
533         $otherPage = \BookStack\Page::take(1)->get()->first();
534         $this->checkAccessPermission('page-delete-all', [
535             $otherPage->getUrl() . '/delete'
536         ], [
537             $otherPage->getUrl() => 'Delete'
538         ]);
539
540         $bookUrl = $otherPage->book->getUrl();
541         $this->visit($otherPage->getUrl())->visit($otherPage->getUrl() . '/delete')
542             ->press('Confirm')
543             ->seePageIs($bookUrl)
544             ->dontSeeInElement('.book-content', $otherPage->name);
545     }
546
547     public function test_public_role_not_visible_in_user_edit_screen()
548     {
549         $user = \BookStack\User::first();
550         $this->asAdmin()->visit('/settings/users/' . $user->id)
551             ->seeElement('#roles-admin')
552             ->dontSeeElement('#roles-public');
553     }
554
555     public function test_public_role_not_visible_in_role_listing()
556     {
557         $this->asAdmin()->visit('/settings/roles')
558             ->see('Admin')
559             ->dontSee('Public');
560     }
561
562     public function test_public_role_not_visible_in_default_role_setting()
563     {
564         $this->asAdmin()->visit('/settings')
565             ->seeElement('[data-role-name="admin"]')
566             ->dontSeeElement('[data-role-name="public"]');
567
568     }
569
570 }