3 class RolesTest extends BrowserKitTest
7 public function setUp()
10 $this->user = $this->getViewer();
13 protected function getViewer()
15 $role = \BookStack\Role::getRole('viewer');
16 $viewer = $this->getNewBlankUser();
17 $viewer->attachRole($role);;
22 * Give the given user some permissions.
23 * @param \BookStack\User $user
24 * @param array $permissions
26 protected function giveUserPermissions(\BookStack\User $user, $permissions = [])
28 $newRole = $this->createNewRole($permissions);
29 $user->attachRole($newRole);
31 $user->permissions(false);
35 * Create a new basic role for testing purposes.
36 * @param array $permissions
39 protected function createNewRole($permissions = [])
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);
47 public function test_admin_can_see_settings()
49 $this->asAdmin()->visit('/settings')->see('Settings');
52 public function test_cannot_delete_admin_role()
54 $adminRole = \BookStack\Role::getRole('admin');
55 $deletePageUrl = '/settings/roles/delete/' . $adminRole->id;
56 $this->asAdmin()->visit($deletePageUrl)
58 ->seePageIs($deletePageUrl)
59 ->see('cannot be deleted');
62 public function test_role_cannot_be_deleted_if_default()
64 $newRole = $this->createNewRole();
65 $this->setSettings(['registration-role' => $newRole->id]);
67 $deletePageUrl = '/settings/roles/delete/' . $newRole->id;
68 $this->asAdmin()->visit($deletePageUrl)
70 ->seePageIs($deletePageUrl)
71 ->see('cannot be deleted');
74 public function test_role_create_update_delete_flow()
76 $testRoleName = 'Test Role';
77 $testRoleDesc = 'a little test description';
78 $testRoleUpdateName = 'An Super Updated role';
81 $this->asAdmin()->visit('/settings')
83 ->seePageIs('/settings/roles')
84 ->click('Create New Role')
85 ->type('Test Role', 'display_name')
86 ->type('A little test description', 'description')
88 ->seeInDatabase('roles', ['display_name' => $testRoleName, 'name' => 'test-role', 'description' => $testRoleDesc])
89 ->seePageIs('/settings/roles');
91 $this->asAdmin()->visit('/settings/roles')
93 ->click($testRoleName)
94 ->type($testRoleUpdateName, '#display_name')
96 ->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'name' => 'test-role', 'description' => $testRoleDesc])
97 ->seePageIs('/settings/roles');
99 $this->asAdmin()->visit('/settings/roles')
100 ->click($testRoleUpdateName)
101 ->click('Delete Role')
102 ->see($testRoleUpdateName)
104 ->seePageIs('/settings/roles')
105 ->dontSee($testRoleUpdateName);
108 public function test_manage_user_permission()
110 $this->actingAs($this->user)->visit('/')->visit('/settings/users')
112 $this->giveUserPermissions($this->user, ['users-manage']);
113 $this->actingAs($this->user)->visit('/')->visit('/settings/users')
114 ->seePageIs('/settings/users');
117 public function test_user_roles_manage_permission()
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')
127 public function test_settings_manage_permission()
129 $this->actingAs($this->user)->visit('/')->visit('/settings')
131 $this->giveUserPermissions($this->user, ['settings-manage']);
132 $this->actingAs($this->user)->visit('/')->visit('/settings')
133 ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved');
136 public function test_restrictions_manage_all_permission()
138 $page = \BookStack\Page::take(1)->get()->first();
139 $this->actingAs($this->user)->visit($page->getUrl())
140 ->dontSee('Permissions')
141 ->visit($page->getUrl() . '/permissions')
143 $this->giveUserPermissions($this->user, ['restrictions-manage-all']);
144 $this->actingAs($this->user)->visit($page->getUrl())
146 ->click('Permissions')
147 ->see('Page Permissions')->seePageIs($page->getUrl() . '/permissions');
150 public function test_restrictions_manage_own_permission()
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')
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')
165 $this->giveUserPermissions($this->user, ['restrictions-manage-own']);
167 // Check can't restrict other's content
168 $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
169 ->dontSee('Permissions')
170 ->visit($otherUsersPage->getUrl() . '/permissions')
172 // Check can restrict own content
173 $this->actingAs($this->user)->visit($content['page']->getUrl())
175 ->click('Permissions')
176 ->seePageIs($content['page']->getUrl() . '/permissions');
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
186 private function checkAccessPermission($permission, $accessUrls = [], $visibles = [])
188 foreach ($accessUrls as $url) {
189 $this->actingAs($this->user)->visit('/')->visit($url)
192 foreach ($visibles as $url => $text) {
193 $this->actingAs($this->user)->visit('/')->visit($url)
194 ->dontSeeInElement('.action-buttons',$text);
197 $this->giveUserPermissions($this->user, [$permission]);
199 foreach ($accessUrls as $url) {
200 $this->actingAs($this->user)->visit('/')->visit($url)
203 foreach ($visibles as $url => $text) {
204 $this->actingAs($this->user)->visit('/')->visit($url)
209 public function test_books_create_all_permissions()
211 $this->checkAccessPermission('book-create-all', [
214 '/books' => 'Create New Book'
217 $this->visit('/books/create')
218 ->type('test book', 'name')
219 ->type('book desc', 'description')
221 ->seePageIs('/books/test-book');
224 public function test_books_edit_own_permission()
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'
231 $ownBook->getUrl() => 'Edit'
234 $this->visit($otherBook->getUrl())
235 ->dontSeeInElement('.action-buttons', 'Edit')
236 ->visit($otherBook->getUrl() . '/edit')
240 public function test_books_edit_all_permission()
242 $otherBook = \BookStack\Book::take(1)->get()->first();
243 $this->checkAccessPermission('book-update-all', [
244 $otherBook->getUrl() . '/edit'
246 $otherBook->getUrl() => 'Edit'
250 public function test_books_delete_own_permission()
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'
258 $ownBook->getUrl() => 'Delete'
261 $this->visit($otherBook->getUrl())
262 ->dontSeeInElement('.action-buttons', 'Delete')
263 ->visit($otherBook->getUrl() . '/delete')
265 $this->visit($ownBook->getUrl())->visit($ownBook->getUrl() . '/delete')
267 ->seePageIs('/books')
268 ->dontSee($ownBook->name);
271 public function test_books_delete_all_permission()
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'
278 $otherBook->getUrl() => 'Delete'
281 $this->visit($otherBook->getUrl())->visit($otherBook->getUrl() . '/delete')
283 ->seePageIs('/books')
284 ->dontSee($otherBook->name);
287 public function test_chapter_create_own_permissions()
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', [
295 $ownBook->getUrl() => 'New Chapter'
298 $this->visit($baseUrl . '/create')
299 ->type('test chapter', 'name')
300 ->type('chapter desc', 'description')
301 ->press('Save Chapter')
302 ->seePageIs($baseUrl . '/test-chapter');
304 $this->visit($book->getUrl())
305 ->dontSeeInElement('.action-buttons', 'New Chapter')
306 ->visit($book->getUrl() . '/chapter/create')
310 public function test_chapter_create_all_permissions()
312 $book = \BookStack\Book::take(1)->get()->first();
313 $baseUrl = $book->getUrl() . '/chapter';
314 $this->checkAccessPermission('chapter-create-all', [
317 $book->getUrl() => 'New Chapter'
320 $this->visit($baseUrl . '/create')
321 ->type('test chapter', 'name')
322 ->type('chapter desc', 'description')
323 ->press('Save Chapter')
324 ->seePageIs($baseUrl . '/test-chapter');
327 public function test_chapter_edit_own_permission()
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'
334 $ownChapter->getUrl() => 'Edit'
337 $this->visit($otherChapter->getUrl())
338 ->dontSeeInElement('.action-buttons', 'Edit')
339 ->visit($otherChapter->getUrl() . '/edit')
343 public function test_chapter_edit_all_permission()
345 $otherChapter = \BookStack\Chapter::take(1)->get()->first();
346 $this->checkAccessPermission('chapter-update-all', [
347 $otherChapter->getUrl() . '/edit'
349 $otherChapter->getUrl() => 'Edit'
353 public function test_chapter_delete_own_permission()
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'
361 $ownChapter->getUrl() => 'Delete'
364 $bookUrl = $ownChapter->book->getUrl();
365 $this->visit($otherChapter->getUrl())
366 ->dontSeeInElement('.action-buttons', 'Delete')
367 ->visit($otherChapter->getUrl() . '/delete')
369 $this->visit($ownChapter->getUrl())->visit($ownChapter->getUrl() . '/delete')
371 ->seePageIs($bookUrl)
372 ->dontSeeInElement('.book-content', $ownChapter->name);
375 public function test_chapter_delete_all_permission()
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'
382 $otherChapter->getUrl() => 'Delete'
385 $bookUrl = $otherChapter->book->getUrl();
386 $this->visit($otherChapter->getUrl())->visit($otherChapter->getUrl() . '/delete')
388 ->seePageIs($bookUrl)
389 ->dontSeeInElement('.book-content', $otherChapter->name);
392 public function test_page_create_own_permissions()
394 $book = \BookStack\Book::take(1)->get()->first();
395 $chapter = \BookStack\Chapter::take(1)->get()->first();
397 $entities = $this->createEntityChainBelongingToUser($this->user);
398 $ownBook = $entities['book'];
399 $ownChapter = $entities['chapter'];
401 $baseUrl = $ownBook->getUrl() . '/page';
403 $createUrl = $baseUrl . '/create';
404 $createUrlChapter = $ownChapter->getUrl() . '/create-page';
405 $accessUrls = [$createUrl, $createUrlChapter];
407 foreach ($accessUrls as $url) {
408 $this->actingAs($this->user)->visit('/')->visit($url)
412 $this->checkAccessPermission('page-create-own', [], [
413 $ownBook->getUrl() => 'New Page',
414 $ownChapter->getUrl() => 'New Page'
417 $this->giveUserPermissions($this->user, ['page-create-own']);
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);
425 $this->visit($baseUrl . '/create')
426 ->type('test page', 'name')
427 ->type('page desc', 'html')
429 ->seePageIs($baseUrl . '/test-page');
431 $this->visit($book->getUrl())
432 ->dontSeeInElement('.action-buttons', 'New Page')
433 ->visit($book->getUrl() . '/page/create')
435 $this->visit($chapter->getUrl())
436 ->dontSeeInElement('.action-buttons', 'New Page')
437 ->visit($chapter->getUrl() . '/create-page')
441 public function test_page_create_all_permissions()
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';
448 $createUrlChapter = $chapter->getUrl() . '/create-page';
449 $accessUrls = [$createUrl, $createUrlChapter];
451 foreach ($accessUrls as $url) {
452 $this->actingAs($this->user)->visit('/')->visit($url)
456 $this->checkAccessPermission('page-create-all', [], [
457 $book->getUrl() => 'New Page',
458 $chapter->getUrl() => 'New Page'
461 $this->giveUserPermissions($this->user, ['page-create-all']);
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);
469 $this->visit($baseUrl . '/create')
470 ->type('test page', 'name')
471 ->type('page desc', 'html')
473 ->seePageIs($baseUrl . '/test-page');
475 $this->visit($chapter->getUrl() . '/create-page')
476 ->type('new test page', 'name')
477 ->type('page desc', 'html')
479 ->seePageIs($baseUrl . '/new-test-page');
482 public function test_page_edit_own_permission()
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'
489 $ownPage->getUrl() => 'Edit'
492 $this->visit($otherPage->getUrl())
493 ->dontSeeInElement('.action-buttons', 'Edit')
494 ->visit($otherPage->getUrl() . '/edit')
498 public function test_page_edit_all_permission()
500 $otherPage = \BookStack\Page::take(1)->get()->first();
501 $this->checkAccessPermission('page-update-all', [
502 $otherPage->getUrl() . '/edit'
504 $otherPage->getUrl() => 'Edit'
508 public function test_page_delete_own_permission()
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'
516 $ownPage->getUrl() => 'Delete'
519 $bookUrl = $ownPage->book->getUrl();
520 $this->visit($otherPage->getUrl())
521 ->dontSeeInElement('.action-buttons', 'Delete')
522 ->visit($otherPage->getUrl() . '/delete')
524 $this->visit($ownPage->getUrl())->visit($ownPage->getUrl() . '/delete')
526 ->seePageIs($bookUrl)
527 ->dontSeeInElement('.book-content', $ownPage->name);
530 public function test_page_delete_all_permission()
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'
537 $otherPage->getUrl() => 'Delete'
540 $bookUrl = $otherPage->book->getUrl();
541 $this->visit($otherPage->getUrl())->visit($otherPage->getUrl() . '/delete')
543 ->seePageIs($bookUrl)
544 ->dontSeeInElement('.book-content', $otherPage->name);
547 public function test_public_role_visible_in_user_edit_screen()
549 $user = \BookStack\User::first();
550 $this->asAdmin()->visit('/settings/users/' . $user->id)
551 ->seeElement('#roles-admin')
552 ->seeElement('#roles-public');
555 public function test_public_role_visible_in_role_listing()
557 $this->asAdmin()->visit('/settings/roles')
562 public function test_public_role_visible_in_default_role_setting()
564 $this->asAdmin()->visit('/settings')
565 ->seeElement('[data-role-name="admin"]')
566 ->seeElement('[data-role-name="public"]');
570 public function test_public_role_not_deleteable()
572 $this->asAdmin()->visit('/settings/roles')
575 ->click('Delete Role')
578 ->see('Cannot be deleted');
583 public function test_image_delete_own_permission()
585 $this->giveUserPermissions($this->user, ['image-update-all']);
586 $page = \BookStack\Page::first();
587 $image = factory(\BookStack\Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $this->user->id, 'updated_by' => $this->user->id]);
589 $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
590 ->seeStatusCode(403);
592 $this->giveUserPermissions($this->user, ['image-delete-own']);
594 $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
596 ->dontSeeInDatabase('images', ['id' => $image->id]);
599 public function test_image_delete_all_permission()
601 $this->giveUserPermissions($this->user, ['image-update-all']);
602 $admin = $this->getAdmin();
603 $page = \BookStack\Page::first();
604 $image = factory(\BookStack\Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $admin->id, 'updated_by' => $admin->id]);
606 $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
607 ->seeStatusCode(403);
609 $this->giveUserPermissions($this->user, ['image-delete-own']);
611 $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
612 ->seeStatusCode(403);
614 $this->giveUserPermissions($this->user, ['image-delete-all']);
616 $this->actingAs($this->user)->json('delete', '/images/' . $image->id)
618 ->dontSeeInDatabase('images', ['id' => $image->id]);