6 use BookStack\Repos\EntityRepo;
8 class RestrictionsTest extends BrowserKitTest
21 public function setUp()
24 $this->user = $this->getEditor();
25 $this->viewer = $this->getViewer();
28 protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = [])
31 $this->user->roles->first(),
32 $this->viewer->roles->first(),
34 parent::setEntityRestrictions($entity, $actions, $roles);
37 public function test_book_view_restriction()
39 $book = Book::first();
40 $bookPage = $book->pages->first();
41 $bookChapter = $book->chapters->first();
43 $bookUrl = $book->getUrl();
44 $this->actingAs($this->user)
46 ->seePageIs($bookUrl);
48 $this->setEntityRestrictions($book, []);
50 $this->forceVisit($bookUrl)
51 ->see('Book not found');
52 $this->forceVisit($bookPage->getUrl())
53 ->see('Page not found');
54 $this->forceVisit($bookChapter->getUrl())
55 ->see('Chapter not found');
57 $this->setEntityRestrictions($book, ['view']);
59 $this->visit($bookUrl)
61 $this->visit($bookPage->getUrl())
62 ->see($bookPage->name);
63 $this->visit($bookChapter->getUrl())
64 ->see($bookChapter->name);
67 public function test_book_create_restriction()
69 $book = Book::first();
71 $bookUrl = $book->getUrl();
72 $this->actingAs($this->viewer)
74 ->dontSeeInElement('.action-buttons', 'New Page')
75 ->dontSeeInElement('.action-buttons', 'New Chapter');
76 $this->actingAs($this->user)
78 ->seeInElement('.action-buttons', 'New Page')
79 ->seeInElement('.action-buttons', 'New Chapter');
81 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
83 $this->forceVisit($bookUrl . '/create-chapter')
84 ->see('You do not have permission')->seePageIs('/');
85 $this->forceVisit($bookUrl . '/create-page')
86 ->see('You do not have permission')->seePageIs('/');
87 $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
88 ->dontSeeInElement('.action-buttons', 'New Chapter');
90 $this->setEntityRestrictions($book, ['view', 'create']);
92 $this->visit($bookUrl . '/create-chapter')
93 ->type('test chapter', 'name')
94 ->type('test description for chapter', 'description')
95 ->press('Save Chapter')
96 ->seePageIs($bookUrl . '/chapter/test-chapter');
97 $this->visit($bookUrl . '/create-page')
98 ->type('test page', 'name')
99 ->type('test content', 'html')
101 ->seePageIs($bookUrl . '/page/test-page');
102 $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
103 ->seeInElement('.action-buttons', 'New Chapter');
106 public function test_book_update_restriction()
108 $book = Book::first();
109 $bookPage = $book->pages->first();
110 $bookChapter = $book->chapters->first();
112 $bookUrl = $book->getUrl();
113 $this->actingAs($this->user)
114 ->visit($bookUrl . '/edit')
117 $this->setEntityRestrictions($book, ['view', 'delete']);
119 $this->forceVisit($bookUrl . '/edit')
120 ->see('You do not have permission')->seePageIs('/');
121 $this->forceVisit($bookPage->getUrl() . '/edit')
122 ->see('You do not have permission')->seePageIs('/');
123 $this->forceVisit($bookChapter->getUrl() . '/edit')
124 ->see('You do not have permission')->seePageIs('/');
126 $this->setEntityRestrictions($book, ['view', 'update']);
128 $this->visit($bookUrl . '/edit')
129 ->seePageIs($bookUrl . '/edit');
130 $this->visit($bookPage->getUrl() . '/edit')
131 ->seePageIs($bookPage->getUrl() . '/edit');
132 $this->visit($bookChapter->getUrl() . '/edit')
133 ->see('Edit Chapter');
136 public function test_book_delete_restriction()
138 $book = Book::first();
139 $bookPage = $book->pages->first();
140 $bookChapter = $book->chapters->first();
142 $bookUrl = $book->getUrl();
143 $this->actingAs($this->user)
144 ->visit($bookUrl . '/delete')
145 ->see('Delete Book');
147 $this->setEntityRestrictions($book, ['view', 'update']);
149 $this->forceVisit($bookUrl . '/delete')
150 ->see('You do not have permission')->seePageIs('/');
151 $this->forceVisit($bookPage->getUrl() . '/delete')
152 ->see('You do not have permission')->seePageIs('/');
153 $this->forceVisit($bookChapter->getUrl() . '/delete')
154 ->see('You do not have permission')->seePageIs('/');
156 $this->setEntityRestrictions($book, ['view', 'delete']);
158 $this->visit($bookUrl . '/delete')
159 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
160 $this->visit($bookPage->getUrl() . '/delete')
161 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
162 $this->visit($bookChapter->getUrl() . '/delete')
163 ->see('Delete Chapter');
166 public function test_chapter_view_restriction()
168 $chapter = \BookStack\Chapter::first();
169 $chapterPage = $chapter->pages->first();
171 $chapterUrl = $chapter->getUrl();
172 $this->actingAs($this->user)
174 ->seePageIs($chapterUrl);
176 $this->setEntityRestrictions($chapter, []);
178 $this->forceVisit($chapterUrl)
179 ->see('Chapter not found');
180 $this->forceVisit($chapterPage->getUrl())
181 ->see('Page not found');
183 $this->setEntityRestrictions($chapter, ['view']);
185 $this->visit($chapterUrl)
186 ->see($chapter->name);
187 $this->visit($chapterPage->getUrl())
188 ->see($chapterPage->name);
191 public function test_chapter_create_restriction()
193 $chapter = \BookStack\Chapter::first();
195 $chapterUrl = $chapter->getUrl();
196 $this->actingAs($this->user)
198 ->seeInElement('.action-buttons', 'New Page');
200 $this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
202 $this->forceVisit($chapterUrl . '/create-page')
203 ->see('You do not have permission')->seePageIs('/');
204 $this->visit($chapterUrl)->dontSeeInElement('.action-buttons', 'New Page');
206 $this->setEntityRestrictions($chapter, ['view', 'create']);
209 $this->visit($chapterUrl . '/create-page')
210 ->type('test page', 'name')
211 ->type('test content', 'html')
213 ->seePageIs($chapter->book->getUrl() . '/page/test-page');
215 $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page');
218 public function test_chapter_update_restriction()
220 $chapter = \BookStack\Chapter::first();
221 $chapterPage = $chapter->pages->first();
223 $chapterUrl = $chapter->getUrl();
224 $this->actingAs($this->user)
225 ->visit($chapterUrl . '/edit')
226 ->see('Edit Chapter');
228 $this->setEntityRestrictions($chapter, ['view', 'delete']);
230 $this->forceVisit($chapterUrl . '/edit')
231 ->see('You do not have permission')->seePageIs('/');
232 $this->forceVisit($chapterPage->getUrl() . '/edit')
233 ->see('You do not have permission')->seePageIs('/');
235 $this->setEntityRestrictions($chapter, ['view', 'update']);
237 $this->visit($chapterUrl . '/edit')
238 ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter');
239 $this->visit($chapterPage->getUrl() . '/edit')
240 ->seePageIs($chapterPage->getUrl() . '/edit');
243 public function test_chapter_delete_restriction()
245 $chapter = \BookStack\Chapter::first();
246 $chapterPage = $chapter->pages->first();
248 $chapterUrl = $chapter->getUrl();
249 $this->actingAs($this->user)
250 ->visit($chapterUrl . '/delete')
251 ->see('Delete Chapter');
253 $this->setEntityRestrictions($chapter, ['view', 'update']);
255 $this->forceVisit($chapterUrl . '/delete')
256 ->see('You do not have permission')->seePageIs('/');
257 $this->forceVisit($chapterPage->getUrl() . '/delete')
258 ->see('You do not have permission')->seePageIs('/');
260 $this->setEntityRestrictions($chapter, ['view', 'delete']);
262 $this->visit($chapterUrl . '/delete')
263 ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter');
264 $this->visit($chapterPage->getUrl() . '/delete')
265 ->seePageIs($chapterPage->getUrl() . '/delete')->see('Delete Page');
268 public function test_page_view_restriction()
270 $page = \BookStack\Page::first();
272 $pageUrl = $page->getUrl();
273 $this->actingAs($this->user)
275 ->seePageIs($pageUrl);
277 $this->setEntityRestrictions($page, ['update', 'delete']);
279 $this->forceVisit($pageUrl)
280 ->see('Page not found');
282 $this->setEntityRestrictions($page, ['view']);
284 $this->visit($pageUrl)
288 public function test_page_update_restriction()
290 $page = \BookStack\Chapter::first();
292 $pageUrl = $page->getUrl();
293 $this->actingAs($this->user)
294 ->visit($pageUrl . '/edit')
295 ->seeInField('name', $page->name);
297 $this->setEntityRestrictions($page, ['view', 'delete']);
299 $this->forceVisit($pageUrl . '/edit')
300 ->see('You do not have permission')->seePageIs('/');
302 $this->setEntityRestrictions($page, ['view', 'update']);
304 $this->visit($pageUrl . '/edit')
305 ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name);
308 public function test_page_delete_restriction()
310 $page = \BookStack\Page::first();
312 $pageUrl = $page->getUrl();
313 $this->actingAs($this->user)
314 ->visit($pageUrl . '/delete')
315 ->see('Delete Page');
317 $this->setEntityRestrictions($page, ['view', 'update']);
319 $this->forceVisit($pageUrl . '/delete')
320 ->see('You do not have permission')->seePageIs('/');
322 $this->setEntityRestrictions($page, ['view', 'delete']);
324 $this->visit($pageUrl . '/delete')
325 ->seePageIs($pageUrl . '/delete')->see('Delete Page');
328 public function test_book_restriction_form()
330 $book = Book::first();
331 $this->asAdmin()->visit($book->getUrl() . '/permissions')
332 ->see('Book Permissions')
333 ->check('restricted')
334 ->check('restrictions[2][view]')
335 ->press('Save Permissions')
336 ->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
337 ->seeInDatabase('entity_permissions', [
338 'restrictable_id' => $book->id,
339 'restrictable_type' => 'BookStack\Book',
345 public function test_chapter_restriction_form()
347 $chapter = \BookStack\Chapter::first();
348 $this->asAdmin()->visit($chapter->getUrl() . '/permissions')
349 ->see('Chapter Permissions')
350 ->check('restricted')
351 ->check('restrictions[2][update]')
352 ->press('Save Permissions')
353 ->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
354 ->seeInDatabase('entity_permissions', [
355 'restrictable_id' => $chapter->id,
356 'restrictable_type' => 'BookStack\Chapter',
362 public function test_page_restriction_form()
364 $page = \BookStack\Page::first();
365 $this->asAdmin()->visit($page->getUrl() . '/permissions')
366 ->see('Page Permissions')
367 ->check('restricted')
368 ->check('restrictions[2][delete]')
369 ->press('Save Permissions')
370 ->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
371 ->seeInDatabase('entity_permissions', [
372 'restrictable_id' => $page->id,
373 'restrictable_type' => 'BookStack\Page',
379 public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
381 $chapter = \BookStack\Chapter::first();
382 $page = $chapter->pages->first();
383 $page2 = $chapter->pages[2];
385 $this->setEntityRestrictions($page, []);
387 $this->actingAs($this->user)
388 ->visit($page2->getUrl())
389 ->dontSeeInElement('.sidebar-page-list', $page->name);
392 public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
394 $chapter = \BookStack\Chapter::first();
395 $page = $chapter->pages->first();
397 $this->setEntityRestrictions($page, []);
399 $this->actingAs($this->user)
400 ->visit($chapter->getUrl())
401 ->dontSeeInElement('.sidebar-page-list', $page->name);
404 public function test_restricted_pages_not_visible_on_chapter_pages()
406 $chapter = \BookStack\Chapter::first();
407 $page = $chapter->pages->first();
409 $this->setEntityRestrictions($page, []);
411 $this->actingAs($this->user)
412 ->visit($chapter->getUrl())
413 ->dontSee($page->name);
416 public function test_book_create_restriction_override()
418 $book = Book::first();
420 $bookUrl = $book->getUrl();
421 $this->actingAs($this->viewer)
423 ->dontSeeInElement('.action-buttons', 'New Page')
424 ->dontSeeInElement('.action-buttons', 'New Chapter');
426 $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
428 $this->forceVisit($bookUrl . '/create-chapter')
429 ->see('You do not have permission')->seePageIs('/');
430 $this->forceVisit($bookUrl . '/create-page')
431 ->see('You do not have permission')->seePageIs('/');
432 $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
433 ->dontSeeInElement('.action-buttons', 'New Chapter');
435 $this->setEntityRestrictions($book, ['view', 'create']);
437 $this->visit($bookUrl . '/create-chapter')
438 ->type('test chapter', 'name')
439 ->type('test description for chapter', 'description')
440 ->press('Save Chapter')
441 ->seePageIs($bookUrl . '/chapter/test-chapter');
442 $this->visit($bookUrl . '/create-page')
443 ->type('test page', 'name')
444 ->type('test content', 'html')
446 ->seePageIs($bookUrl . '/page/test-page');
447 $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
448 ->seeInElement('.action-buttons', 'New Chapter');
451 public function test_book_update_restriction_override()
453 $book = Book::first();
454 $bookPage = $book->pages->first();
455 $bookChapter = $book->chapters->first();
457 $bookUrl = $book->getUrl();
458 $this->actingAs($this->viewer)
459 ->visit($bookUrl . '/edit')
460 ->dontSee('Edit Book');
462 $this->setEntityRestrictions($book, ['view', 'delete']);
464 $this->forceVisit($bookUrl . '/edit')
465 ->see('You do not have permission')->seePageIs('/');
466 $this->forceVisit($bookPage->getUrl() . '/edit')
467 ->see('You do not have permission')->seePageIs('/');
468 $this->forceVisit($bookChapter->getUrl() . '/edit')
469 ->see('You do not have permission')->seePageIs('/');
471 $this->setEntityRestrictions($book, ['view', 'update']);
473 $this->visit($bookUrl . '/edit')
474 ->seePageIs($bookUrl . '/edit');
475 $this->visit($bookPage->getUrl() . '/edit')
476 ->seePageIs($bookPage->getUrl() . '/edit');
477 $this->visit($bookChapter->getUrl() . '/edit')
478 ->see('Edit Chapter');
481 public function test_book_delete_restriction_override()
483 $book = Book::first();
484 $bookPage = $book->pages->first();
485 $bookChapter = $book->chapters->first();
487 $bookUrl = $book->getUrl();
488 $this->actingAs($this->viewer)
489 ->visit($bookUrl . '/delete')
490 ->dontSee('Delete Book');
492 $this->setEntityRestrictions($book, ['view', 'update']);
494 $this->forceVisit($bookUrl . '/delete')
495 ->see('You do not have permission')->seePageIs('/');
496 $this->forceVisit($bookPage->getUrl() . '/delete')
497 ->see('You do not have permission')->seePageIs('/');
498 $this->forceVisit($bookChapter->getUrl() . '/delete')
499 ->see('You do not have permission')->seePageIs('/');
501 $this->setEntityRestrictions($book, ['view', 'delete']);
503 $this->visit($bookUrl . '/delete')
504 ->seePageIs($bookUrl . '/delete')->see('Delete Book');
505 $this->visit($bookPage->getUrl() . '/delete')
506 ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
507 $this->visit($bookChapter->getUrl() . '/delete')
508 ->see('Delete Chapter');
511 public function test_page_visible_if_has_permissions_when_book_not_visible()
513 $book = Book::first();
515 $this->setEntityRestrictions($book, []);
517 $bookChapter = $book->chapters->first();
518 $bookPage = $bookChapter->pages->first();
519 $this->setEntityRestrictions($bookPage, ['view']);
521 $this->actingAs($this->viewer);
522 $this->get($bookPage->getUrl());
523 $this->assertResponseOk();
524 $this->see($bookPage->name);
525 $this->dontSee(substr($book->name, 0, 15));
526 $this->dontSee(substr($bookChapter->name, 0, 15));
529 public function test_book_sort_view_permission()
531 $firstBook = Book::first();
532 $secondBook = Book::find(2);
533 $thirdBook = Book::find(3);
535 $this->setEntityRestrictions($firstBook, ['view', 'update']);
536 $this->setEntityRestrictions($secondBook, ['view']);
537 $this->setEntityRestrictions($thirdBook, ['view', 'update']);
539 // Test sort page visibility
540 $this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort')
541 ->see('You do not have permission')
544 // Check sort page on first book
545 $this->actingAs($this->user)->visit($firstBook->getUrl() . '/sort')
546 ->see($thirdBook->name)
547 ->dontSee($secondBook->name);
550 public function test_book_sort_permission() {
551 $firstBook = Book::first();
552 $secondBook = Book::find(2);
554 $this->setEntityRestrictions($firstBook, ['view', 'update']);
555 $this->setEntityRestrictions($secondBook, ['view']);
557 $firstBookChapter = $this->app[EntityRepo::class]->createFromInput('chapter',
558 ['name' => 'first book chapter'], $firstBook);
559 $secondBookChapter = $this->app[EntityRepo::class]->createFromInput('chapter',
560 ['name' => 'second book chapter'], $secondBook);
562 // Create request data
565 'id' => $firstBookChapter->id,
567 'parentChapter' => false,
569 'book' => $secondBook->id
573 // Move chapter from first book to a second book
574 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
576 ->see('You do not have permission')
581 'id' => $secondBookChapter->id,
583 'parentChapter' => false,
585 'book' => $firstBook->id
589 // Move chapter from second book to first book
590 $this->actingAs($this->user)->put($firstBook->getUrl() . '/sort', ['sort-tree' => json_encode($reqData)])
592 ->see('You do not have permission')
596 public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible()
598 $book = Book::first();
599 $this->setEntityRestrictions($book, []);
600 $bookChapter = $book->chapters->first();
601 $this->setEntityRestrictions($bookChapter, ['view']);
603 $this->actingAs($this->user)->visit($bookChapter->getUrl())
604 ->dontSee('New Page');
606 $this->setEntityRestrictions($bookChapter, ['view', 'create']);
608 $this->actingAs($this->user)->visit($bookChapter->getUrl())
611 ->type('test page', 'name')
612 ->type('test content', 'html')
614 ->seePageIs($book->getUrl('/page/test-page'))
615 ->seeStatusCode(200);