3 class RolesTest extends TestCase
7 public function setUp()
10 $this->user = $this->getNewBlankUser();
14 * Give the given user some permissions.
15 * @param \BookStack\User $user
16 * @param array $permissions
18 protected function giveUserPermissions(\BookStack\User $user, $permissions = [])
20 $newRole = $this->createNewRole($permissions);
21 $user->attachRole($newRole);
23 $user->permissions(false);
27 * Create a new basic role for testing purposes.
28 * @param array $permissions
31 protected function createNewRole($permissions = [])
33 $permissionRepo = app('BookStack\Repos\PermissionsRepo');
34 $roleData = factory(\BookStack\Role::class)->make()->toArray();
35 $roleData['permissions'] = array_flip($permissions);
36 return $permissionRepo->saveNewRole($roleData);
39 public function test_admin_can_see_settings()
41 $this->asAdmin()->visit('/settings')->see('Settings');
44 public function test_cannot_delete_admin_role()
46 $adminRole = \BookStack\Role::getRole('admin');
47 $deletePageUrl = '/settings/roles/delete/' . $adminRole->id;
48 $this->asAdmin()->visit($deletePageUrl)
50 ->seePageIs($deletePageUrl)
51 ->see('cannot be deleted');
54 public function test_role_cannot_be_deleted_if_default()
56 $newRole = $this->createNewRole();
57 $this->setSettings(['registration-role' => $newRole->id]);
59 $deletePageUrl = '/settings/roles/delete/' . $newRole->id;
60 $this->asAdmin()->visit($deletePageUrl)
62 ->seePageIs($deletePageUrl)
63 ->see('cannot be deleted');
66 public function test_role_create_update_delete_flow()
68 $testRoleName = 'Test Role';
69 $testRoleDesc = 'a little test description';
70 $testRoleUpdateName = 'An Super Updated role';
73 $this->asAdmin()->visit('/settings')
75 ->seePageIs('/settings/roles')
76 ->click('Add new role')
77 ->type('Test Role', 'display_name')
78 ->type('A little test description', 'description')
80 ->seeInDatabase('roles', ['display_name' => $testRoleName, 'name' => 'test-role', 'description' => $testRoleDesc])
81 ->seePageIs('/settings/roles');
83 $this->asAdmin()->visit('/settings/roles')
85 ->click($testRoleName)
86 ->type($testRoleUpdateName, '#display_name')
88 ->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'name' => 'test-role', 'description' => $testRoleDesc])
89 ->seePageIs('/settings/roles');
91 $this->asAdmin()->visit('/settings/roles')
92 ->click($testRoleUpdateName)
93 ->click('Delete Role')
94 ->see($testRoleUpdateName)
96 ->seePageIs('/settings/roles')
97 ->dontSee($testRoleUpdateName);
100 public function test_manage_user_permission()
102 $this->actingAs($this->user)->visit('/')->visit('/settings/users')
104 $this->giveUserPermissions($this->user, ['users-manage']);
105 $this->actingAs($this->user)->visit('/')->visit('/settings/users')
106 ->seePageIs('/settings/users');
109 public function test_user_roles_manage_permission()
111 $this->actingAs($this->user)->visit('/')->visit('/settings/roles')
112 ->seePageIs('/')->visit('/settings/roles/1')->seePageIs('/');
113 $this->giveUserPermissions($this->user, ['user-roles-manage']);
114 $this->actingAs($this->user)->visit('/settings/roles')
115 ->seePageIs('/settings/roles')->click('Admin')
119 public function test_settings_manage_permission()
121 $this->actingAs($this->user)->visit('/')->visit('/settings')
123 $this->giveUserPermissions($this->user, ['settings-manage']);
124 $this->actingAs($this->user)->visit('/')->visit('/settings')
125 ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved');
128 public function test_restrictions_manage_all_permission()
130 $page = \BookStack\Page::take(1)->get()->first();
131 $this->actingAs($this->user)->visit($page->getUrl())
132 ->dontSee('Restrict')
133 ->visit($page->getUrl() . '/restrict')
135 $this->giveUserPermissions($this->user, ['restrictions-manage-all']);
136 $this->actingAs($this->user)->visit($page->getUrl())
139 ->see('Page Restrictions')->seePageIs($page->getUrl() . '/restrict');
142 public function test_restrictions_manage_own_permission()
144 $otherUsersPage = \BookStack\Page::take(1)->get()->first();
145 $content = $this->createEntityChainBelongingToUser($this->user);
146 // Check can't restrict other's content
147 $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
148 ->dontSee('Restrict')
149 ->visit($otherUsersPage->getUrl() . '/restrict')
151 // Check can't restrict own content
152 $this->actingAs($this->user)->visit($content['page']->getUrl())
153 ->dontSee('Restrict')
154 ->visit($content['page']->getUrl() . '/restrict')
157 $this->giveUserPermissions($this->user, ['restrictions-manage-own']);
159 // Check can't restrict other's content
160 $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
161 ->dontSee('Restrict')
162 ->visit($otherUsersPage->getUrl() . '/restrict')
164 // Check can restrict own content
165 $this->actingAs($this->user)->visit($content['page']->getUrl())
168 ->seePageIs($content['page']->getUrl() . '/restrict');
172 * Check a standard entity access permission
173 * @param string $permission
174 * @param array $accessUrls Urls that are only accessible after having the permission
175 * @param array $visibles Check this text, In the buttons toolbar, is only visible with the permission
176 * @param null $callback
178 private function checkAccessPermission($permission, $accessUrls = [], $visibles = [])
180 foreach ($accessUrls as $url) {
181 $this->actingAs($this->user)->visit('/')->visit($url)
184 foreach ($visibles as $url => $text) {
185 $this->actingAs($this->user)->visit('/')->visit($url)
186 ->dontSeeInElement('.action-buttons',$text);
189 $this->giveUserPermissions($this->user, [$permission]);
191 foreach ($accessUrls as $url) {
192 $this->actingAs($this->user)->visit('/')->visit($url)
195 foreach ($visibles as $url => $text) {
196 $this->actingAs($this->user)->visit('/')->visit($url)
201 public function test_books_create_all_permissions()
203 $this->checkAccessPermission('book-create-all', [
206 '/books' => 'Add new book'
209 $this->visit('/books/create')
210 ->type('test book', 'name')
211 ->type('book desc', 'description')
213 ->seePageIs('/books/test-book');
216 public function test_books_edit_own_permission()
218 $otherBook = \BookStack\Book::take(1)->get()->first();
219 $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
220 $this->checkAccessPermission('book-update-own', [
221 $ownBook->getUrl() . '/edit'
223 $ownBook->getUrl() => 'Edit'
226 $this->visit($otherBook->getUrl())
227 ->dontSeeInElement('.action-buttons', 'Edit')
228 ->visit($otherBook->getUrl() . '/edit')
232 public function test_books_edit_all_permission()
234 $otherBook = \BookStack\Book::take(1)->get()->first();
235 $this->checkAccessPermission('book-update-all', [
236 $otherBook->getUrl() . '/edit'
238 $otherBook->getUrl() => 'Edit'
242 public function test_books_delete_own_permission()
244 $this->giveUserPermissions($this->user, ['book-update-all']);
245 $otherBook = \BookStack\Book::take(1)->get()->first();
246 $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
247 $this->checkAccessPermission('book-delete-own', [
248 $ownBook->getUrl() . '/delete'
250 $ownBook->getUrl() => 'Delete'
253 $this->visit($otherBook->getUrl())
254 ->dontSeeInElement('.action-buttons', 'Delete')
255 ->visit($otherBook->getUrl() . '/delete')
257 $this->visit($ownBook->getUrl())->visit($ownBook->getUrl() . '/delete')
259 ->seePageIs('/books')
260 ->dontSee($ownBook->name);
263 public function test_books_delete_all_permission()
265 $this->giveUserPermissions($this->user, ['book-update-all']);
266 $otherBook = \BookStack\Book::take(1)->get()->first();
267 $this->checkAccessPermission('book-delete-all', [
268 $otherBook->getUrl() . '/delete'
270 $otherBook->getUrl() => 'Delete'
273 $this->visit($otherBook->getUrl())->visit($otherBook->getUrl() . '/delete')
275 ->seePageIs('/books')
276 ->dontSee($otherBook->name);
279 public function test_chapter_create_own_permissions()
281 $book = \BookStack\Book::take(1)->get()->first();
282 $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
283 $baseUrl = $ownBook->getUrl() . '/chapter';
284 $this->checkAccessPermission('chapter-create-own', [
287 $ownBook->getUrl() => 'New Chapter'
290 $this->visit($baseUrl . '/create')
291 ->type('test chapter', 'name')
292 ->type('chapter desc', 'description')
293 ->press('Save Chapter')
294 ->seePageIs($baseUrl . '/test-chapter');
296 $this->visit($book->getUrl())
297 ->dontSeeInElement('.action-buttons', 'New Chapter')
298 ->visit($book->getUrl() . '/chapter/create')
302 public function test_chapter_create_all_permissions()
304 $book = \BookStack\Book::take(1)->get()->first();
305 $baseUrl = $book->getUrl() . '/chapter';
306 $this->checkAccessPermission('chapter-create-all', [
309 $book->getUrl() => 'New Chapter'
312 $this->visit($baseUrl . '/create')
313 ->type('test chapter', 'name')
314 ->type('chapter desc', 'description')
315 ->press('Save Chapter')
316 ->seePageIs($baseUrl . '/test-chapter');
319 public function test_chapter_edit_own_permission()
321 $otherChapter = \BookStack\Chapter::take(1)->get()->first();
322 $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
323 $this->checkAccessPermission('chapter-update-own', [
324 $ownChapter->getUrl() . '/edit'
326 $ownChapter->getUrl() => 'Edit'
329 $this->visit($otherChapter->getUrl())
330 ->dontSeeInElement('.action-buttons', 'Edit')
331 ->visit($otherChapter->getUrl() . '/edit')
335 public function test_chapter_edit_all_permission()
337 $otherChapter = \BookStack\Chapter::take(1)->get()->first();
338 $this->checkAccessPermission('chapter-update-all', [
339 $otherChapter->getUrl() . '/edit'
341 $otherChapter->getUrl() => 'Edit'
345 public function test_chapter_delete_own_permission()
347 $this->giveUserPermissions($this->user, ['chapter-update-all']);
348 $otherChapter = \BookStack\Chapter::take(1)->get()->first();
349 $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
350 $this->checkAccessPermission('chapter-delete-own', [
351 $ownChapter->getUrl() . '/delete'
353 $ownChapter->getUrl() => 'Delete'
356 $bookUrl = $ownChapter->book->getUrl();
357 $this->visit($otherChapter->getUrl())
358 ->dontSeeInElement('.action-buttons', 'Delete')
359 ->visit($otherChapter->getUrl() . '/delete')
361 $this->visit($ownChapter->getUrl())->visit($ownChapter->getUrl() . '/delete')
363 ->seePageIs($bookUrl)
364 ->dontSeeInElement('.book-content', $ownChapter->name);
367 public function test_chapter_delete_all_permission()
369 $this->giveUserPermissions($this->user, ['chapter-update-all']);
370 $otherChapter = \BookStack\Chapter::take(1)->get()->first();
371 $this->checkAccessPermission('chapter-delete-all', [
372 $otherChapter->getUrl() . '/delete'
374 $otherChapter->getUrl() => 'Delete'
377 $bookUrl = $otherChapter->book->getUrl();
378 $this->visit($otherChapter->getUrl())->visit($otherChapter->getUrl() . '/delete')
380 ->seePageIs($bookUrl)
381 ->dontSeeInElement('.book-content', $otherChapter->name);
384 public function test_page_create_own_permissions()
386 $book = \BookStack\Book::take(1)->get()->first();
387 $chapter = \BookStack\Chapter::take(1)->get()->first();
389 $entities = $this->createEntityChainBelongingToUser($this->user);
390 $ownBook = $entities['book'];
391 $ownChapter = $entities['chapter'];
393 $baseUrl = $ownBook->getUrl() . '/page';
395 $createUrl = $baseUrl . '/create';
396 $createUrlChapter = $ownChapter->getUrl() . '/create-page';
397 $accessUrls = [$createUrl, $createUrlChapter];
399 foreach ($accessUrls as $url) {
400 $this->actingAs($this->user)->visit('/')->visit($url)
404 $this->checkAccessPermission('page-create-own', [], [
405 $ownBook->getUrl() => 'New Page',
406 $ownChapter->getUrl() => 'New Page'
409 $this->giveUserPermissions($this->user, ['page-create-own']);
411 foreach ($accessUrls as $index => $url) {
412 $this->actingAs($this->user)->visit('/')->visit($url);
413 $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
414 $this->seePageIs($expectedUrl);
417 $this->visit($baseUrl . '/create')
418 ->type('test page', 'name')
419 ->type('page desc', 'html')
421 ->seePageIs($baseUrl . '/test-page');
423 $this->visit($book->getUrl())
424 ->dontSeeInElement('.action-buttons', 'New Page')
425 ->visit($book->getUrl() . '/page/create')
427 $this->visit($chapter->getUrl())
428 ->dontSeeInElement('.action-buttons', 'New Page')
429 ->visit($chapter->getUrl() . '/create-page')
433 public function test_page_create_all_permissions()
435 $book = \BookStack\Book::take(1)->get()->first();
436 $chapter = \BookStack\Chapter::take(1)->get()->first();
437 $baseUrl = $book->getUrl() . '/page';
438 $createUrl = $baseUrl . '/create';
440 $createUrlChapter = $chapter->getUrl() . '/create-page';
441 $accessUrls = [$createUrl, $createUrlChapter];
443 foreach ($accessUrls as $url) {
444 $this->actingAs($this->user)->visit('/')->visit($url)
448 $this->checkAccessPermission('page-create-all', [], [
449 $book->getUrl() => 'New Page',
450 $chapter->getUrl() => 'New Page'
453 $this->giveUserPermissions($this->user, ['page-create-all']);
455 foreach ($accessUrls as $index => $url) {
456 $this->actingAs($this->user)->visit('/')->visit($url);
457 $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
458 $this->seePageIs($expectedUrl);
461 $this->visit($baseUrl . '/create')
462 ->type('test page', 'name')
463 ->type('page desc', 'html')
465 ->seePageIs($baseUrl . '/test-page');
467 $this->visit($chapter->getUrl() . '/create-page')
468 ->type('new test page', 'name')
469 ->type('page desc', 'html')
471 ->seePageIs($baseUrl . '/new-test-page');
474 public function test_page_edit_own_permission()
476 $otherPage = \BookStack\Page::take(1)->get()->first();
477 $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
478 $this->checkAccessPermission('page-update-own', [
479 $ownPage->getUrl() . '/edit'
481 $ownPage->getUrl() => 'Edit'
484 $this->visit($otherPage->getUrl())
485 ->dontSeeInElement('.action-buttons', 'Edit')
486 ->visit($otherPage->getUrl() . '/edit')
490 public function test_page_edit_all_permission()
492 $otherPage = \BookStack\Page::take(1)->get()->first();
493 $this->checkAccessPermission('page-update-all', [
494 $otherPage->getUrl() . '/edit'
496 $otherPage->getUrl() => 'Edit'
500 public function test_page_delete_own_permission()
502 $this->giveUserPermissions($this->user, ['page-update-all']);
503 $otherPage = \BookStack\Page::take(1)->get()->first();
504 $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
505 $this->checkAccessPermission('page-delete-own', [
506 $ownPage->getUrl() . '/delete'
508 $ownPage->getUrl() => 'Delete'
511 $bookUrl = $ownPage->book->getUrl();
512 $this->visit($otherPage->getUrl())
513 ->dontSeeInElement('.action-buttons', 'Delete')
514 ->visit($otherPage->getUrl() . '/delete')
516 $this->visit($ownPage->getUrl())->visit($ownPage->getUrl() . '/delete')
518 ->seePageIs($bookUrl)
519 ->dontSeeInElement('.book-content', $ownPage->name);
522 public function test_page_delete_all_permission()
524 $this->giveUserPermissions($this->user, ['page-update-all']);
525 $otherPage = \BookStack\Page::take(1)->get()->first();
526 $this->checkAccessPermission('page-delete-all', [
527 $otherPage->getUrl() . '/delete'
529 $otherPage->getUrl() => 'Delete'
532 $bookUrl = $otherPage->book->getUrl();
533 $this->visit($otherPage->getUrl())->visit($otherPage->getUrl() . '/delete')
535 ->seePageIs($bookUrl)
536 ->dontSeeInElement('.book-content', $otherPage->name);