mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-01-31 12:11:37 +01:00
Added further tests, Fixed speed_update issues, improved search result query count
This commit is contained in:
parent
22f8a408fa
commit
62338e4a8f
@ -3,7 +3,6 @@
|
||||
|
||||
class Chapter extends Entity
|
||||
{
|
||||
|
||||
protected $fillable = ['name', 'description', 'priority', 'book_id'];
|
||||
|
||||
public function book()
|
||||
@ -18,7 +17,7 @@ class Chapter extends Entity
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
$bookSlug = isset($this->bookSlug) ? $this->bookSlug : $this->book->slug;
|
||||
$bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug;
|
||||
return '/books/' . $bookSlug. '/chapter/' . $this->slug;
|
||||
}
|
||||
|
||||
|
@ -69,19 +69,18 @@ abstract class Entity extends Model
|
||||
* @param $type
|
||||
* @return bool
|
||||
*/
|
||||
public function isA($type)
|
||||
public static function isA($type)
|
||||
{
|
||||
return $this->getName() === strtolower($type);
|
||||
return static::getName() === strtolower($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class name.
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
public static function getName()
|
||||
{
|
||||
$fullClassName = get_class($this);
|
||||
return strtolower(array_slice(explode('\\', $fullClassName), -1, 1)[0]);
|
||||
return strtolower(array_slice(explode('\\', static::class), -1, 1)[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,6 +101,15 @@ abstract class Entity extends Model
|
||||
foreach ($wheres as $whereTerm) {
|
||||
$search->where($whereTerm[0], $whereTerm[1], $whereTerm[2]);
|
||||
}
|
||||
|
||||
if (!static::isA('book')) {
|
||||
$search = $search->with('book');
|
||||
}
|
||||
|
||||
if(static::isA('page')) {
|
||||
$search = $search->with('chapter');
|
||||
}
|
||||
|
||||
return $search->get();
|
||||
}
|
||||
|
||||
|
@ -150,14 +150,16 @@ class BookController extends Controller
|
||||
{
|
||||
$this->checkPermission('book-update');
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
$bookChildren = $this->bookRepo->getChildren($book);
|
||||
$books = $this->bookRepo->getAll();
|
||||
return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books]);
|
||||
return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
|
||||
}
|
||||
|
||||
public function getSortItem($bookSlug)
|
||||
{
|
||||
$book = $this->bookRepo->getBySlug($bookSlug);
|
||||
return view('books/sort-box', ['book' => $book]);
|
||||
$bookChildren = $this->bookRepo->getChildren($book);
|
||||
return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,6 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Show the form for creating a new chapter.
|
||||
*
|
||||
* @param $bookSlug
|
||||
* @return Response
|
||||
*/
|
||||
@ -46,7 +45,6 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Store a newly created chapter in storage.
|
||||
*
|
||||
* @param $bookSlug
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
@ -62,8 +60,8 @@ class ChapterController extends Controller
|
||||
$chapter = $this->chapterRepo->newFromInput($request->all());
|
||||
$chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id);
|
||||
$chapter->priority = $this->bookRepo->getNewPriority($book);
|
||||
$chapter->created_by = Auth::user()->id;
|
||||
$chapter->updated_by = Auth::user()->id;
|
||||
$chapter->created_by = auth()->user()->id;
|
||||
$chapter->updated_by = auth()->user()->id;
|
||||
$book->chapters()->save($chapter);
|
||||
Activity::add($chapter, 'chapter_create', $book->id);
|
||||
return redirect($chapter->getUrl());
|
||||
@ -71,7 +69,6 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Display the specified chapter.
|
||||
*
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return Response
|
||||
@ -87,7 +84,6 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified chapter.
|
||||
*
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return Response
|
||||
@ -102,7 +98,6 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Update the specified chapter in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
@ -115,7 +110,7 @@ class ChapterController extends Controller
|
||||
$chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
|
||||
$chapter->fill($request->all());
|
||||
$chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id, $chapter->id);
|
||||
$chapter->updated_by = Auth::user()->id;
|
||||
$chapter->updated_by = auth()->user()->id;
|
||||
$chapter->save();
|
||||
Activity::add($chapter, 'chapter_update', $book->id);
|
||||
return redirect($chapter->getUrl());
|
||||
@ -137,7 +132,6 @@ class ChapterController extends Controller
|
||||
|
||||
/**
|
||||
* Remove the specified chapter from storage.
|
||||
*
|
||||
* @param $bookSlug
|
||||
* @param $chapterSlug
|
||||
* @return Response
|
||||
|
@ -141,7 +141,7 @@ class BookRepo
|
||||
*/
|
||||
public function getNewPriority($book)
|
||||
{
|
||||
$lastElem = $book->children()->pop();
|
||||
$lastElem = $this->getChildren($book)->pop();
|
||||
return $lastElem ? $lastElem->priority + 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -13,33 +13,35 @@
|
||||
|
||||
$factory->define(BookStack\User::class, function ($faker) {
|
||||
return [
|
||||
'name' => $faker->name,
|
||||
'email' => $faker->email,
|
||||
'password' => str_random(10),
|
||||
'name' => $faker->name,
|
||||
'email' => $faker->email,
|
||||
'password' => str_random(10),
|
||||
'remember_token' => str_random(10),
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(BookStack\Book::class, function ($faker) {
|
||||
return [
|
||||
'name' => $faker->sentence,
|
||||
'slug' => str_random(10),
|
||||
'name' => $faker->sentence,
|
||||
'slug' => str_random(10),
|
||||
'description' => $faker->paragraph
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(BookStack\Chapter::class, function ($faker) {
|
||||
return [
|
||||
'name' => $faker->sentence,
|
||||
'slug' => str_random(10),
|
||||
'name' => $faker->sentence,
|
||||
'slug' => str_random(10),
|
||||
'description' => $faker->paragraph
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(BookStack\Page::class, function ($faker) {
|
||||
$html = '<p>' . implode('</p>', $faker->paragraphs(5)) . '</p>';
|
||||
return [
|
||||
'name' => $faker->sentence,
|
||||
'slug' => str_random(10),
|
||||
'html' => '<p>' . implode('</p>', $faker->paragraphs(5)) . '</p>'
|
||||
'slug' => str_random(10),
|
||||
'html' => $html,
|
||||
'text' => strip_tags($html)
|
||||
];
|
||||
});
|
||||
|
@ -54,36 +54,36 @@ class AddEntityIndexes extends Migration
|
||||
public function down()
|
||||
{
|
||||
Schema::table('books', function (Blueprint $table) {
|
||||
$table->dropIndex('slug');
|
||||
$table->dropIndex('created_by');
|
||||
$table->dropIndex('updated_by');
|
||||
$table->dropIndex('books_slug_index');
|
||||
$table->dropIndex('books_created_by_index');
|
||||
$table->dropIndex('books_updated_by_index');
|
||||
});
|
||||
Schema::table('pages', function (Blueprint $table) {
|
||||
$table->dropIndex('slug');
|
||||
$table->dropIndex('book_id');
|
||||
$table->dropIndex('chapter_id');
|
||||
$table->dropIndex('priority');
|
||||
$table->dropIndex('created_by');
|
||||
$table->dropIndex('updated_by');
|
||||
$table->dropIndex('pages_slug_index');
|
||||
$table->dropIndex('pages_book_id_index');
|
||||
$table->dropIndex('pages_chapter_id_index');
|
||||
$table->dropIndex('pages_priority_index');
|
||||
$table->dropIndex('pages_created_by_index');
|
||||
$table->dropIndex('pages_updated_by_index');
|
||||
});
|
||||
Schema::table('page_revisions', function (Blueprint $table) {
|
||||
$table->dropIndex('page_id');
|
||||
$table->dropIndex('page_revisions_page_id_index');
|
||||
});
|
||||
Schema::table('chapters', function (Blueprint $table) {
|
||||
$table->dropIndex('slug');
|
||||
$table->dropIndex('book_id');
|
||||
$table->dropIndex('priority');
|
||||
$table->dropIndex('created_by');
|
||||
$table->dropIndex('updated_by');
|
||||
$table->dropIndex('chapters_slug_index');
|
||||
$table->dropIndex('chapters_book_id_index');
|
||||
$table->dropIndex('chapters_priority_index');
|
||||
$table->dropIndex('chapters_created_by_index');
|
||||
$table->dropIndex('chapters_updated_by_index');
|
||||
});
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->dropIndex('book_id');
|
||||
$table->dropIndex('user_id');
|
||||
$table->dropIndex('entity_id');
|
||||
$table->dropIndex('activities_book_id_index');
|
||||
$table->dropIndex('activities_user_id_index');
|
||||
$table->dropIndex('activities_entity_id_index');
|
||||
});
|
||||
Schema::table('views', function (Blueprint $table) {
|
||||
$table->dropIndex('user_id');
|
||||
$table->dropIndex('entity_id');
|
||||
$table->dropIndex('views_user_id_index');
|
||||
$table->dropIndex('views_viewable_id_index');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
12
readme.md
12
readme.md
@ -55,6 +55,18 @@ location / {
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. To use you will need PHPUnit installed and accessible via command line. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the following database name, user name and password defined as `bookstack-test`. You will have to create that database and credentials before testing.
|
||||
|
||||
The testing database will also need migrating and seeding beforehand. This can be done with the following commands:
|
||||
|
||||
```
|
||||
php artisan migrate --database=mysql_testing
|
||||
php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
|
||||
```
|
||||
|
||||
Once done you can run `phpunit` in the application root directory to run all tests.
|
||||
|
||||
## License
|
||||
|
||||
|
@ -47,8 +47,8 @@
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-3 text-center">
|
||||
<form action="/search/all" method="GET" class="search-box">
|
||||
<input type="text" name="term" tabindex="2" value="{{ isset($searchTerm) ? $searchTerm : '' }}">
|
||||
<button class="text-button"><i class="zmdi zmdi-search"></i></button>
|
||||
<input id="header-search-box-input" type="text" name="term" tabindex="2" value="{{ isset($searchTerm) ? $searchTerm : '' }}">
|
||||
<button id="header-search-box-button" type="submit" class="text-button"><i class="zmdi zmdi-search"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-5">
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="sort-box" data-type="book" data-id="{{ $book->id }}">
|
||||
<h3 class="text-book"><i class="zmdi zmdi-book"></i>{{ $book->name }}</h3>
|
||||
<ul class="sortable-page-list sort-list">
|
||||
@foreach($book->children() as $bookChild)
|
||||
@foreach($bookChildren as $bookChild)
|
||||
<li data-id="{{$bookChild->id}}" data-type="{{ $bookChild->getName() }}" class="text-{{ $bookChild->getName() }}">
|
||||
<i class="zmdi {{ $bookChild->isA('chapter') ? 'zmdi-collection-bookmark':'zmdi-file-text'}}"></i>{{ $bookChild->name }}
|
||||
@if($bookChild->isA('chapter'))
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-8" id="sort-boxes">
|
||||
|
||||
@include('books/sort-box', ['book' => $book])
|
||||
@include('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -51,6 +51,34 @@ class EntityTest extends TestCase
|
||||
return \BookStack\Book::find($book->id);
|
||||
}
|
||||
|
||||
public function testBookSortPageShows()
|
||||
{
|
||||
$books = \BookStack\Book::all();
|
||||
$bookToSort = $books[0];
|
||||
$this->asAdmin()
|
||||
->visit($bookToSort->getUrl())
|
||||
->click('Sort')
|
||||
->seePageIs($bookToSort->getUrl() . '/sort')
|
||||
->seeStatusCode(200)
|
||||
->see($bookToSort->name)
|
||||
// Ensure page shows other books
|
||||
->see($books[1]->name);
|
||||
}
|
||||
|
||||
public function testBookSortItemReturnsBookContent()
|
||||
{
|
||||
$books = \BookStack\Book::all();
|
||||
$bookToSort = $books[0];
|
||||
$firstPage = $bookToSort->pages[0];
|
||||
$firstChapter = $bookToSort->chapters[0];
|
||||
$this->asAdmin()
|
||||
->visit($bookToSort->getUrl() . '/sort-item')
|
||||
// Ensure book details are returned
|
||||
->see($bookToSort->name)
|
||||
->see($firstPage->name)
|
||||
->see($firstChapter->name);
|
||||
}
|
||||
|
||||
public function pageCreation($chapter)
|
||||
{
|
||||
$page = factory(\BookStack\Page::class)->make([
|
||||
@ -118,12 +146,29 @@ class EntityTest extends TestCase
|
||||
// Ensure duplicate names are given different slugs
|
||||
$this->asAdmin()
|
||||
->visit('/books/create')
|
||||
->submitForm('Save Book', $book->toArray())
|
||||
->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 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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user