public function test_draft_pages_not_visible_by_others() { $book = \BookStack\Book::first(); $chapter = $book->chapters->first(); $newUser = $this->getEditor(); $this->actingAs($newUser)->visit('/')->visit($book->getUrl() . '/page/create')->visit($chapter->getUrl() . '/create-page')->visit($book->getUrl())->seeInElement('.page-list', 'New Page'); $this->asAdmin()->visit($book->getUrl())->dontSeeInElement('.page-list', 'New Page')->visit($chapter->getUrl())->dontSeeInElement('.page-list', 'New Page'); }
public function testBooksViewable() { $this->setSettings(['app-public' => 'true']); $books = \BookStack\Book::orderBy('name', 'asc')->take(10)->get(); $bookToVisit = $books[1]; // Check books index page is showing $this->visit('/books')->seeStatusCode(200)->see($books[0]->name)->click($bookToVisit->name)->seePageIs($bookToVisit->getUrl())->see($bookToVisit->name)->see($bookToVisit->chapters()->first()->name); }
public function bookCreation() { $book = factory(\BookStack\Book::class)->make(['name' => 'My First Book']); $this->asAdmin()->visit('/books')->click('Add new book')->seePageIs('/books/create')->type($book->name, '#name')->type($book->description, '#description')->press('Save Book')->seePageIs('/books/my-first-book')->see($book->name)->see($book->description); // Ensure duplicate names are given different slugs $this->asAdmin()->visit('/books/create')->type($book->name, '#name')->type($book->description, '#description')->press('Save Book')->seePageIs('/books/my-first-book-2'); $book = \BookStack\Book::where('slug', '=', 'my-first-book')->first(); return $book; }
public function bookCreation() { $book = factory(\BookStack\Book::class)->make(['name' => 'My First Book']); $this->asAdmin()->visit('/books')->click('Add new book')->seePageIs('/books/create')->type($book->name, '#name')->type($book->description, '#description')->press('Save Book')->seePageIs('/books/my-first-book')->see($book->name)->see($book->description); // Ensure duplicate names are given different slugs $this->asAdmin()->visit('/books/create')->type($book->name, '#name')->type($book->description, '#description')->press('Save Book'); $expectedPattern = '/\\/books\\/my-first-book-[0-9a-zA-Z]{3}/'; $this->assertRegExp($expectedPattern, $this->currentUri, "Did not land on expected page [{$expectedPattern}].\n"); $book = \BookStack\Book::where('slug', '=', 'my-first-book')->first(); return $book; }
public function test_chapter_move() { $chapter = \BookStack\Chapter::first(); $currentBook = $chapter->book; $pageToCheck = $chapter->pages->first(); $newBook = \BookStack\Book::where('id', '!=', $currentBook->id)->first(); $this->asAdmin()->visit($chapter->getUrl() . '/move')->see('Move Chapter')->see($chapter->name)->type('book:' . $newBook->id, 'entity_selection')->press('Move Chapter'); $chapter = \BookStack\Chapter::find($chapter->id); $this->seePageIs($chapter->getUrl()); $this->assertTrue($chapter->book->id === $newBook->id, 'Chapter Book is now the new book'); $this->visit($newBook->getUrl())->seeInNthElement('.activity-list-item', 0, 'moved chapter')->seeInNthElement('.activity-list-item', 0, $chapter->name); $pageToCheck = \BookStack\Page::find($pageToCheck->id); $this->assertTrue($pageToCheck->book_id === $newBook->id, 'Chapter child page\'s book id has changed to the new book'); $this->visit($pageToCheck->getUrl())->see($newBook->name); }
public function test_books_search_listing() { $book = \BookStack\Book::all()->last(); $this->asAdmin()->visit('/search/books?term=' . $book->name)->see('Book Search Results')->see('.entity-list', $book->name); }
/** * Get all child objects of a book. * Returns a sorted collection of Pages and Chapters. * Loads the bookslug onto child elements to prevent access database access for getting the slug. * @param Book $book * @return mixed */ public function getChildren(Book $book) { $pages = $book->pages()->where('chapter_id', '=', 0)->get(); $chapters = $book->chapters()->with('pages')->get(); $children = $pages->merge($chapters); $bookSlug = $book->slug; $children->each(function ($child) use($bookSlug) { $child->setAttribute('bookSlug', $bookSlug); if ($child->isA('chapter')) { $child->pages->each(function ($page) use($bookSlug) { $page->setAttribute('bookSlug', $bookSlug); }); } }); return $children->sortBy('priority'); }
public function test_empty_book_search_redirects_back() { $book = \BookStack\Book::all()->first(); $this->asAdmin()->visit('/books')->visit('/search/book/' . $book->id . '?term=')->seePageIs('/books'); }
public function testPageSearch() { $book = \BookStack\Book::all()->first(); $page = $book->pages->first(); $this->asAdmin()->visit('/')->type($page->name, 'term')->press('header-search-box-button')->see('Search Results')->see($page->name)->click($page->name)->seePageIs($page->getUrl()); }
/** * Get all child objects of a book. * Returns a sorted collection of Pages and Chapters. * Loads the book slug onto child elements to prevent access database access for getting the slug. * @param Book $book * @param bool $filterDrafts * @return mixed */ public function getChildren(Book $book, $filterDrafts = false) { $pageQuery = $book->pages()->where('chapter_id', '=', 0); $pageQuery = $this->permissionService->enforcePageRestrictions($pageQuery, 'view'); if ($filterDrafts) { $pageQuery = $pageQuery->where('draft', '=', false); } $pages = $pageQuery->get(); $chapterQuery = $book->chapters()->with(['pages' => function ($query) use($filterDrafts) { $this->permissionService->enforcePageRestrictions($query, 'view'); if ($filterDrafts) { $query->where('draft', '=', false); } }]); $chapterQuery = $this->permissionService->enforceChapterRestrictions($chapterQuery, 'view'); $chapters = $chapterQuery->get(); $children = $pages->values(); foreach ($chapters as $chapter) { $children->push($chapter); } $bookSlug = $book->slug; $children->each(function ($child) use($bookSlug) { $child->setAttribute('bookSlug', $bookSlug); if ($child->isA('chapter')) { $child->pages->each(function ($page) use($bookSlug) { $page->setAttribute('bookSlug', $bookSlug); }); $child->pages = $child->pages->sortBy(function ($child, $key) { $score = $child->priority; if ($child->draft) { $score -= 100; } return $score; }); } }); // Sort items with drafts first then by priority. return $children->sortBy(function ($child, $key) { $score = $child->priority; if ($child->isA('page') && $child->draft) { $score -= 100; } return $score; }); }
/** * Save a new page into the system. * Input validation must be done beforehand. * @param array $input * @param Book $book * @param int $chapterId * @return Page */ public function saveNew(array $input, Book $book, $chapterId = null) { $page = $this->newFromInput($input); $page->slug = $this->findSuitableSlug($page->name, $book->id); if ($chapterId) { $page->chapter_id = $chapterId; } $page->html = $this->formatHtml($input['html']); $page->text = strip_tags($page->html); $page->created_by = auth()->user()->id; $page->updated_by = auth()->user()->id; $book->pages()->save($page); return $page; }
public function test_page_create_all_permissions() { $book = \BookStack\Book::take(1)->get()->first(); $chapter = \BookStack\Chapter::take(1)->get()->first(); $baseUrl = $book->getUrl() . '/page'; $createUrl = $baseUrl . '/create'; $createUrlChapter = $chapter->getUrl() . '/create-page'; $accessUrls = [$createUrl, $createUrlChapter]; foreach ($accessUrls as $url) { $this->actingAs($this->user)->visit('/')->visit($url)->seePageIs('/'); } $this->checkAccessPermission('page-create-all', [], [$book->getUrl() => 'New Page', $chapter->getUrl() => 'New Page']); $this->giveUserPermissions($this->user, ['page-create-all']); foreach ($accessUrls as $index => $url) { $this->actingAs($this->user)->visit('/')->visit($url); $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl(); $this->seePageIs($expectedUrl); } $this->visit($baseUrl . '/create')->type('test page', 'name')->type('page desc', 'html')->press('Save Page')->seePageIs($baseUrl . '/test-page'); $this->visit($chapter->getUrl() . '/create-page')->type('new test page', 'name')->type('page desc', 'html')->press('Save Page')->seePageIs($baseUrl . '/new-test-page'); }
/** * Get a new draft page instance. * @param Book $book * @param Chapter|bool $chapter * @return static */ public function getDraftPage(Book $book, $chapter = false) { $page = $this->page->newInstance(); $page->name = 'New Page'; $page->created_by = auth()->user()->id; $page->updated_by = auth()->user()->id; $page->draft = true; if ($chapter) { $page->chapter_id = $chapter->id; } $book->pages()->save($page); $this->permissionService->buildJointPermissionsForEntity($page); return $page; }
public function test_popular_books() { $books = \BookStack\Book::all()->take(10); $this->asAdmin()->visit('/books')->dontSeeInElement('#popular', $books[0]->name)->dontSeeInElement('#popular', $books[1]->name)->visit($books[0]->getUrl())->visit($books[1]->getUrl())->visit($books[0]->getUrl())->visit('/books')->seeInNthElement('#popular .book', 0, $books[0]->name)->seeInNthElement('#popular .book', 1, $books[1]->name); }
/** * Create a new chapter from request input. * @param $input * @param Book $book * @return Chapter */ public function createFromInput($input, Book $book) { $chapter = $this->chapter->newInstance($input); $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id); $chapter->created_by = user()->id; $chapter->updated_by = user()->id; $chapter = $book->chapters()->save($chapter); $this->permissionService->buildJointPermissionsForEntity($chapter); return $chapter; }
public function test_book_delete_restriction_override() { $book = \BookStack\Book::first(); $bookPage = $book->pages->first(); $bookChapter = $book->chapters->first(); $bookUrl = $book->getUrl(); $this->actingAs($this->viewer)->visit($bookUrl . '/delete')->dontSee('Delete Book'); $this->setEntityRestrictions($book, ['view', 'update']); $this->forceVisit($bookUrl . '/delete')->see('You do not have permission')->seePageIs('/'); $this->forceVisit($bookPage->getUrl() . '/delete')->see('You do not have permission')->seePageIs('/'); $this->forceVisit($bookChapter->getUrl() . '/delete')->see('You do not have permission')->seePageIs('/'); $this->setEntityRestrictions($book, ['view', 'delete']); $this->visit($bookUrl . '/delete')->seePageIs($bookUrl . '/delete')->see('Delete Book'); $this->visit($bookPage->getUrl() . '/delete')->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page'); $this->visit($bookChapter->getUrl() . '/delete')->see('Delete Chapter'); }