Merge branch 'cw1998-feature/create-book-button-on-shelves'
This commit is contained in:
commit
95d4149d5e
|
@ -577,7 +577,7 @@ class PermissionService
|
||||||
$query2->where('has_permission_own', '=', 1)
|
$query2->where('has_permission_own', '=', 1)
|
||||||
->where('created_by', '=', $userId);
|
->where('created_by', '=', $userId);
|
||||||
});
|
});
|
||||||
}) ;
|
});
|
||||||
|
|
||||||
if (!is_null($entityClass)) {
|
if (!is_null($entityClass)) {
|
||||||
$entityInstance = app()->make($entityClass);
|
$entityInstance = app()->make($entityClass);
|
||||||
|
|
|
@ -26,7 +26,9 @@ class Bookshelf extends Entity
|
||||||
*/
|
*/
|
||||||
public function books()
|
public function books()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Book::class, 'bookshelves_books', 'bookshelf_id', 'book_id')->orderBy('order', 'asc');
|
return $this->belongsToMany(Book::class, 'bookshelves_books', 'bookshelf_id', 'book_id')
|
||||||
|
->withPivot('order')
|
||||||
|
->orderBy('order', 'asc');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -577,6 +577,21 @@ class EntityRepo
|
||||||
$shelf->books()->sync($syncData);
|
$shelf->books()->sync($syncData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a Book to a BookShelf.
|
||||||
|
* @param Bookshelf $shelf
|
||||||
|
* @param Book $book
|
||||||
|
*/
|
||||||
|
public function appendBookToShelf(Bookshelf $shelf, Book $book)
|
||||||
|
{
|
||||||
|
if ($shelf->contains($book)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxOrder = $shelf->books()->max('order');
|
||||||
|
$shelf->books()->attach($book->id, ['order' => $maxOrder + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the book that an entity belongs to.
|
* Change the book that an entity belongs to.
|
||||||
* @param string $type
|
* @param string $type
|
||||||
|
|
|
@ -75,30 +75,55 @@ class BookController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for creating a new book.
|
* Show the form for creating a new book.
|
||||||
|
* @param string $shelfSlug
|
||||||
* @return Response
|
* @return Response
|
||||||
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create(string $shelfSlug = null)
|
||||||
{
|
{
|
||||||
|
$bookshelf = null;
|
||||||
|
if ($shelfSlug !== null) {
|
||||||
|
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug);
|
||||||
|
$this->checkOwnablePermission('bookshelf-update', $bookshelf);
|
||||||
|
}
|
||||||
|
|
||||||
$this->checkPermission('book-create-all');
|
$this->checkPermission('book-create-all');
|
||||||
$this->setPageTitle(trans('entities.books_create'));
|
$this->setPageTitle(trans('entities.books_create'));
|
||||||
return view('books.create');
|
return view('books.create', [
|
||||||
|
'bookshelf' => $bookshelf
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a newly created book in storage.
|
* Store a newly created book in storage.
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
|
* @param string $shelfSlug
|
||||||
* @return Response
|
* @return Response
|
||||||
|
* @throws \BookStack\Exceptions\NotFoundException
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request, string $shelfSlug = null)
|
||||||
{
|
{
|
||||||
$this->checkPermission('book-create-all');
|
$this->checkPermission('book-create-all');
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'description' => 'string|max:1000'
|
'description' => 'string|max:1000'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$bookshelf = null;
|
||||||
|
if ($shelfSlug !== null) {
|
||||||
|
$bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug);
|
||||||
|
$this->checkOwnablePermission('bookshelf-update', $bookshelf);
|
||||||
|
}
|
||||||
|
|
||||||
$book = $this->entityRepo->createFromInput('book', $request->all());
|
$book = $this->entityRepo->createFromInput('book', $request->all());
|
||||||
Activity::add($book, 'book_create', $book->id);
|
Activity::add($book, 'book_create', $book->id);
|
||||||
|
|
||||||
|
if ($bookshelf) {
|
||||||
|
$this->entityRepo->appendBookToShelf($bookshelf, $book);
|
||||||
|
Activity::add($bookshelf, 'bookshelf_update');
|
||||||
|
}
|
||||||
|
|
||||||
return redirect($book->getUrl());
|
return redirect($book->getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ return [
|
||||||
'shelves_create' => 'Create New Shelf',
|
'shelves_create' => 'Create New Shelf',
|
||||||
'shelves_popular' => 'Popular Shelves',
|
'shelves_popular' => 'Popular Shelves',
|
||||||
'shelves_new' => 'New Shelves',
|
'shelves_new' => 'New Shelves',
|
||||||
|
'shelves_new_action' => 'New Shelf',
|
||||||
'shelves_popular_empty' => 'The most popular shelves will appear here.',
|
'shelves_popular_empty' => 'The most popular shelves will appear here.',
|
||||||
'shelves_new_empty' => 'The most recently created shelves will appear here.',
|
'shelves_new_empty' => 'The most recently created shelves will appear here.',
|
||||||
'shelves_save' => 'Save Shelf',
|
'shelves_save' => 'Save Shelf',
|
||||||
|
@ -104,6 +105,7 @@ return [
|
||||||
'books_popular' => 'Popular Books',
|
'books_popular' => 'Popular Books',
|
||||||
'books_recent' => 'Recent Books',
|
'books_recent' => 'Recent Books',
|
||||||
'books_new' => 'New Books',
|
'books_new' => 'New Books',
|
||||||
|
'books_new_action' => 'New Book',
|
||||||
'books_popular_empty' => 'The most popular books will appear here.',
|
'books_popular_empty' => 'The most popular books will appear here.',
|
||||||
'books_new_empty' => 'The most recently created books will appear here.',
|
'books_new_empty' => 'The most recently created books will appear here.',
|
||||||
'books_create' => 'Create New Book',
|
'books_create' => 'Create New Book',
|
||||||
|
|
|
@ -3,21 +3,31 @@
|
||||||
@section('body')
|
@section('body')
|
||||||
<div class="container small">
|
<div class="container small">
|
||||||
<div class="my-s">
|
<div class="my-s">
|
||||||
@include('partials.breadcrumbs', ['crumbs' => [
|
@if (isset($bookshelf))
|
||||||
'/books' => [
|
@include('partials.breadcrumbs', ['crumbs' => [
|
||||||
'text' => trans('entities.books'),
|
$bookshelf,
|
||||||
'icon' => 'book'
|
$bookshelf->getUrl('/create-book') => [
|
||||||
],
|
'text' => trans('entities.books_create'),
|
||||||
'/create-book' => [
|
'icon' => 'add'
|
||||||
'text' => trans('entities.books_create'),
|
]
|
||||||
'icon' => 'add'
|
]])
|
||||||
]
|
@else
|
||||||
]])
|
@include('partials.breadcrumbs', ['crumbs' => [
|
||||||
|
'/books' => [
|
||||||
|
'text' => trans('entities.books'),
|
||||||
|
'icon' => 'book'
|
||||||
|
],
|
||||||
|
'/create-book' => [
|
||||||
|
'text' => trans('entities.books_create'),
|
||||||
|
'icon' => 'add'
|
||||||
|
]
|
||||||
|
]])
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-wrap card">
|
<div class="content-wrap card">
|
||||||
<h1 class="list-heading">{{ trans('entities.books_create') }}</h1>
|
<h1 class="list-heading">{{ trans('entities.books_create') }}</h1>
|
||||||
<form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
|
<form action="{{ isset($bookshelf) ? $bookshelf->getUrl('/create-book') : baseUrl('/books') }}" method="POST" enctype="multipart/form-data">
|
||||||
@include('books.form')
|
@include('books.form')
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
@if($currentUser->can('bookshelf-create-all'))
|
@if($currentUser->can('bookshelf-create-all'))
|
||||||
<a href="{{ baseUrl("/create-shelf") }}" class="icon-list-item">
|
<a href="{{ baseUrl("/create-shelf") }}" class="icon-list-item">
|
||||||
<span>@icon('add')</span>
|
<span>@icon('add')</span>
|
||||||
<span>{{ trans('entities.shelves_create') }}</span>
|
<span>{{ trans('entities.shelves_new_action') }}</span>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
@include('partials.view-toggle', ['view' => $view, 'type' => 'shelf'])
|
@include('partials.view-toggle', ['view' => $view, 'type' => 'shelf'])
|
||||||
|
|
|
@ -23,6 +23,12 @@
|
||||||
<hr>
|
<hr>
|
||||||
<p class="text-muted italic mt-xl mb-m">{{ trans('entities.shelves_empty_contents') }}</p>
|
<p class="text-muted italic mt-xl mb-m">{{ trans('entities.shelves_empty_contents') }}</p>
|
||||||
<div class="icon-list inline block">
|
<div class="icon-list inline block">
|
||||||
|
@if(userCan('book-create-all') && userCan('bookshelf-update', $shelf))
|
||||||
|
<a href="{{ $shelf->getUrl('/create-book') }}" class="icon-list-item text-book">
|
||||||
|
<span class="icon">@icon('add')</span>
|
||||||
|
<span>{{ trans('entities.books_create') }}</span>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
@if(userCan('bookshelf-update', $shelf))
|
@if(userCan('bookshelf-update', $shelf))
|
||||||
<a href="{{ $shelf->getUrl('/edit') }}" class="icon-list-item text-bookshelf">
|
<a href="{{ $shelf->getUrl('/edit') }}" class="icon-list-item text-bookshelf">
|
||||||
<span class="icon">@icon('edit')</span>
|
<span class="icon">@icon('edit')</span>
|
||||||
|
@ -74,6 +80,15 @@
|
||||||
<h5>{{ trans('common.actions') }}</h5>
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
<div class="icon-list text-primary">
|
<div class="icon-list text-primary">
|
||||||
|
|
||||||
|
@if(userCan('book-create-all') && userCan('bookshelf-update', $shelf))
|
||||||
|
<a href="{{ $shelf->getUrl('/create-book') }}" class="icon-list-item">
|
||||||
|
<span class="icon">@icon('add')</span>
|
||||||
|
<span>{{ trans('entities.books_new_action') }}</span>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<hr class="primary-background">
|
||||||
|
|
||||||
@if(userCan('bookshelf-update', $shelf))
|
@if(userCan('bookshelf-update', $shelf))
|
||||||
<a href="{{ $shelf->getUrl('/edit') }}" class="icon-list-item">
|
<a href="{{ $shelf->getUrl('/edit') }}" class="icon-list-item">
|
||||||
<span>@icon('edit')</span>
|
<span>@icon('edit')</span>
|
||||||
|
|
|
@ -26,6 +26,9 @@ Route::group(['middleware' => 'auth'], function () {
|
||||||
Route::get('/{slug}/permissions', 'BookshelfController@showPermissions');
|
Route::get('/{slug}/permissions', 'BookshelfController@showPermissions');
|
||||||
Route::put('/{slug}/permissions', 'BookshelfController@permissions');
|
Route::put('/{slug}/permissions', 'BookshelfController@permissions');
|
||||||
Route::post('/{slug}/copy-permissions', 'BookshelfController@copyPermissions');
|
Route::post('/{slug}/copy-permissions', 'BookshelfController@copyPermissions');
|
||||||
|
|
||||||
|
Route::get('/{shelfSlug}/create-book', 'BookController@create');
|
||||||
|
Route::post('/{shelfSlug}/create-book', 'BookController@store');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/create-book', 'BookController@create');
|
Route::get('/create-book', 'BookController@create');
|
||||||
|
|
|
@ -48,7 +48,7 @@ class BookShelfTest extends TestCase
|
||||||
public function test_shelves_page_contains_create_link()
|
public function test_shelves_page_contains_create_link()
|
||||||
{
|
{
|
||||||
$resp = $this->asEditor()->get('/shelves');
|
$resp = $this->asEditor()->get('/shelves');
|
||||||
$resp->assertElementContains('a', 'Create New Shelf');
|
$resp->assertElementContains('a', 'New Shelf');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_shelves_create()
|
public function test_shelves_create()
|
||||||
|
@ -99,9 +99,11 @@ class BookShelfTest extends TestCase
|
||||||
{
|
{
|
||||||
$shelf = Bookshelf::first();
|
$shelf = Bookshelf::first();
|
||||||
$resp = $this->asAdmin()->get($shelf->getUrl());
|
$resp = $this->asAdmin()->get($shelf->getUrl());
|
||||||
|
$resp->assertSee($shelf->getUrl('/create-book'));
|
||||||
$resp->assertSee($shelf->getUrl('/edit'));
|
$resp->assertSee($shelf->getUrl('/edit'));
|
||||||
$resp->assertSee($shelf->getUrl('/permissions'));
|
$resp->assertSee($shelf->getUrl('/permissions'));
|
||||||
$resp->assertSee($shelf->getUrl('/delete'));
|
$resp->assertSee($shelf->getUrl('/delete'));
|
||||||
|
$resp->assertElementContains('a', 'New Book');
|
||||||
$resp->assertElementContains('a', 'Edit');
|
$resp->assertElementContains('a', 'Edit');
|
||||||
$resp->assertElementContains('a', 'Permissions');
|
$resp->assertElementContains('a', 'Permissions');
|
||||||
$resp->assertElementContains('a', 'Delete');
|
$resp->assertElementContains('a', 'Delete');
|
||||||
|
@ -148,6 +150,32 @@ class BookShelfTest extends TestCase
|
||||||
$this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
|
$this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_shelf_create_new_book()
|
||||||
|
{
|
||||||
|
$shelf = Bookshelf::first();
|
||||||
|
$resp = $this->asEditor()->get($shelf->getUrl('/create-book'));
|
||||||
|
|
||||||
|
$resp->assertSee('Create New Book');
|
||||||
|
$resp->assertSee($shelf->getShortName());
|
||||||
|
|
||||||
|
$testName = 'Test Book in Shelf Name';
|
||||||
|
|
||||||
|
$createBookResp = $this->asEditor()->post($shelf->getUrl('/create-book'), [
|
||||||
|
'name' => $testName,
|
||||||
|
'description' => 'Book in shelf description'
|
||||||
|
]);
|
||||||
|
$createBookResp->assertRedirect();
|
||||||
|
|
||||||
|
$newBook = Book::query()->orderBy('id', 'desc')->first();
|
||||||
|
$this->assertDatabaseHas('bookshelves_books', [
|
||||||
|
'bookshelf_id' => $shelf->id,
|
||||||
|
'book_id' => $newBook->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$resp = $this->asEditor()->get($shelf->getUrl());
|
||||||
|
$resp->assertSee($testName);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_shelf_delete()
|
public function test_shelf_delete()
|
||||||
{
|
{
|
||||||
$shelf = Bookshelf::first();
|
$shelf = Bookshelf::first();
|
||||||
|
|
|
@ -215,7 +215,7 @@ class RolesTest extends BrowserKitTest
|
||||||
$this->checkAccessPermission('bookshelf-create-all', [
|
$this->checkAccessPermission('bookshelf-create-all', [
|
||||||
'/create-shelf'
|
'/create-shelf'
|
||||||
], [
|
], [
|
||||||
'/shelves' => 'Create New Shelf'
|
'/shelves' => 'New Shelf'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->visit('/create-shelf')
|
$this->visit('/create-shelf')
|
||||||
|
|
Loading…
Reference in New Issue