From faa3a8b8427a1243a9acec014f789406460d10ba Mon Sep 17 00:00:00 2001 From: Christopher Wilkinson Date: Tue, 2 Apr 2019 16:35:46 +0100 Subject: [PATCH 1/5] Add button to add a book directly from a shelf view --- app/Http/Controllers/BookController.php | 42 ++++++++++++++++++++++--- resources/views/books/create.blade.php | 2 +- resources/views/shelves/show.blade.php | 6 ++++ routes/web.php | 2 ++ tests/Entity/BookShelfTest.php | 10 ++++++ 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 9eb19ce65..325fd1ffa 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -77,21 +77,42 @@ class BookController extends Controller * Show the form for creating a new book. * @return Response */ - public function create() + public function create($shelfSlug = null) { + if ($shelfSlug !== null) { + $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug); + $this->checkOwnablePermission('bookshelf-update', $bookshelf); + } else { + $bookshelf = null; + } + $this->checkPermission('book-create-all'); $this->setPageTitle(trans('entities.books_create')); - return view('books.create'); + return view('books.create', [ + 'bookshelf' => $bookshelf + ]); } /** * Store a newly created book in storage. * - * @param Request $request + * @param Request $request + * @param $shelfSlug * @return Response */ - public function store(Request $request) + public function store(Request $request, $shelfSlug = null) { + if ($shelfSlug !== null) { + $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug); + $this->checkOwnablePermission('bookshelf-update', $bookshelf); + + $shelfBooks = $this->entityRepo->getBookshelfChildren($bookshelf); + $shelfBookIds = $shelfBooks->pluck('id'); + + } else { + $bookshelf = null; + } + $this->checkPermission('book-create-all'); $this->validate($request, [ 'name' => 'required|string|max:255', @@ -99,6 +120,19 @@ class BookController extends Controller ]); $book = $this->entityRepo->createFromInput('book', $request->all()); Activity::add($book, 'book_create', $book->id); + + if ($bookshelf) { + $shelfBookIds = $shelfBookIds->toArray(); + array_unshift($shelfBookIds, $book->id); + + $shelfBookIds = implode(',', $shelfBookIds); + + $this->entityRepo->updateShelfBooks($bookshelf, $shelfBookIds); + Activity::add($bookshelf, 'bookshelf_update'); + + return redirect($bookshelf->getUrl()); + } + return redirect($book->getUrl()); } diff --git a/resources/views/books/create.blade.php b/resources/views/books/create.blade.php index 9079a3bf9..e33ae2bae 100644 --- a/resources/views/books/create.blade.php +++ b/resources/views/books/create.blade.php @@ -17,7 +17,7 @@

{{ trans('entities.books_create') }}

-
+ @include('books.form')
diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php index 0cfaebbd7..77423c144 100644 --- a/resources/views/shelves/show.blade.php +++ b/resources/views/shelves/show.blade.php @@ -23,6 +23,12 @@

{{ trans('entities.shelves_empty_contents') }}

+ @if($currentUser->can('book-create-all')) + + @icon('add') + {{ trans('entities.books_create') }} + + @endif @if(userCan('bookshelf-update', $shelf)) @icon('edit') diff --git a/routes/web.php b/routes/web.php index 7c2c5917e..831d54c85 100644 --- a/routes/web.php +++ b/routes/web.php @@ -26,6 +26,8 @@ Route::group(['middleware' => 'auth'], function () { Route::get('/{slug}/permissions', 'BookshelfController@showPermissions'); Route::put('/{slug}/permissions', 'BookshelfController@permissions'); Route::post('/{slug}/copy-permissions', 'BookshelfController@copyPermissions'); + Route::get('/{slug}/create-book', 'BookController@create'); + Route::post('/{slug}/create-book', 'BookController@store'); }); Route::get('/create-book', 'BookController@create'); diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index 0707fc5ff..a95f31b52 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -99,9 +99,11 @@ class BookShelfTest extends TestCase { $shelf = Bookshelf::first(); $resp = $this->asAdmin()->get($shelf->getUrl()); + $resp->assertSee($shelf->getUrl('/create-book')); $resp->assertSee($shelf->getUrl('/edit')); $resp->assertSee($shelf->getUrl('/permissions')); $resp->assertSee($shelf->getUrl('/delete')); + $resp->assertElementContains('a', 'Create New Book'); $resp->assertElementContains('a', 'Edit'); $resp->assertElementContains('a', 'Permissions'); $resp->assertElementContains('a', 'Delete'); @@ -148,6 +150,14 @@ class BookShelfTest extends TestCase $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->assertSeeText('Create New Book'); + } + public function test_shelf_delete() { $shelf = Bookshelf::first(); From 50a9c71de092eab835b9b3b6a8ffd34aede2e3a2 Mon Sep 17 00:00:00 2001 From: Christopher Wilkinson Date: Wed, 3 Apr 2019 10:05:08 +0100 Subject: [PATCH 2/5] Add tests for creating a book and adding directly to a shelf --- tests/Entity/BookShelfTest.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index a95f31b52..e49c24739 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -155,7 +155,19 @@ class BookShelfTest extends TestCase $shelf = Bookshelf::first(); $resp = $this->asEditor()->get($shelf->getUrl('/create-book')); - $resp->assertSeeText('Create New 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' + ]); + + $resp = $this->asEditor()->get($shelf->getUrl()); + + $resp->assertSee($testName); } public function test_shelf_delete() From d3cd369247a4c49e626264e40528174b309d241c Mon Sep 17 00:00:00 2001 From: Christopher Wilkinson Date: Wed, 3 Apr 2019 10:26:24 +0100 Subject: [PATCH 3/5] Fix phpcs issues --- app/Auth/Permissions/PermissionService.php | 2 +- app/Http/Controllers/BookController.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index 1e1ee3946..7e710edaf 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -577,7 +577,7 @@ class PermissionService $query2->where('has_permission_own', '=', 1) ->where('created_by', '=', $userId); }); - }) ; + }); if (!is_null($entityClass)) { $entityInstance = app()->make($entityClass); diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 325fd1ffa..862d2b021 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -108,7 +108,6 @@ class BookController extends Controller $shelfBooks = $this->entityRepo->getBookshelfChildren($bookshelf); $shelfBookIds = $shelfBooks->pluck('id'); - } else { $bookshelf = null; } From 84419005e73f9b3bc8a6f4d074c27a11df1439dc Mon Sep 17 00:00:00 2001 From: Christopher Wilkinson Date: Mon, 15 Apr 2019 10:56:21 +0100 Subject: [PATCH 4/5] Update create new book button on shelves to 2019 design --- resources/views/books/create.blade.php | 30 +++++++++++++++++--------- resources/views/shelves/show.blade.php | 9 +++++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/resources/views/books/create.blade.php b/resources/views/books/create.blade.php index e33ae2bae..882ce556a 100644 --- a/resources/views/books/create.blade.php +++ b/resources/views/books/create.blade.php @@ -3,16 +3,26 @@ @section('body')
- @include('partials.breadcrumbs', ['crumbs' => [ - '/books' => [ - 'text' => trans('entities.books'), - 'icon' => 'book' - ], - '/create-book' => [ - 'text' => trans('entities.books_create'), - 'icon' => 'add' - ] - ]]) + @if (isset($bookshelf)) + @include('partials.breadcrumbs', ['crumbs' => [ + $bookshelf, + $bookshelf->getUrl('/create-book') => [ + '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
diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php index 77423c144..a57abecb3 100644 --- a/resources/views/shelves/show.blade.php +++ b/resources/views/shelves/show.blade.php @@ -24,7 +24,7 @@

{{ trans('entities.shelves_empty_contents') }}

@if($currentUser->can('book-create-all')) - + @icon('add') {{ trans('entities.books_create') }} @@ -80,6 +80,13 @@
{{ trans('common.actions') }}
+ @if($currentUser->can('book-create-all')) + + @icon('add') + {{ trans('entities.books_create') }} + + @endif + @if(userCan('bookshelf-update', $shelf)) @icon('edit') From 7f3f6e65b9705beabbafa5ceba8636a74ac22138 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 15 Apr 2019 20:43:25 +0100 Subject: [PATCH 5/5] Aligned item creation wording and updated shelf-book-add logic --- app/Entities/Bookshelf.php | 4 ++- app/Entities/Repos/EntityRepo.php | 15 ++++++++++ app/Http/Controllers/BookController.php | 38 ++++++++++--------------- resources/lang/en/entities.php | 2 ++ resources/views/shelves/index.blade.php | 2 +- resources/views/shelves/show.blade.php | 10 ++++--- routes/web.php | 5 ++-- tests/Entity/BookShelfTest.php | 12 ++++++-- tests/Permissions/RolesTest.php | 2 +- 9 files changed, 55 insertions(+), 35 deletions(-) diff --git a/app/Entities/Bookshelf.php b/app/Entities/Bookshelf.php index 08ce8d8cb..1de767fec 100644 --- a/app/Entities/Bookshelf.php +++ b/app/Entities/Bookshelf.php @@ -26,7 +26,9 @@ class Bookshelf extends Entity */ 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'); } /** diff --git a/app/Entities/Repos/EntityRepo.php b/app/Entities/Repos/EntityRepo.php index 6fc2689a5..3bf70c327 100644 --- a/app/Entities/Repos/EntityRepo.php +++ b/app/Entities/Repos/EntityRepo.php @@ -577,6 +577,21 @@ class EntityRepo $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. * @param string $type diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 862d2b021..24e0d784d 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -75,15 +75,16 @@ class BookController extends Controller /** * Show the form for creating a new book. + * @param string $shelfSlug * @return Response + * @throws \BookStack\Exceptions\NotFoundException */ - public function create($shelfSlug = null) + public function create(string $shelfSlug = null) { + $bookshelf = null; if ($shelfSlug !== null) { $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug); $this->checkOwnablePermission('bookshelf-update', $bookshelf); - } else { - $bookshelf = null; } $this->checkPermission('book-create-all'); @@ -97,39 +98,30 @@ class BookController extends Controller * Store a newly created book in storage. * * @param Request $request - * @param $shelfSlug + * @param string $shelfSlug * @return Response + * @throws \BookStack\Exceptions\NotFoundException */ - public function store(Request $request, $shelfSlug = null) + public function store(Request $request, string $shelfSlug = null) { - if ($shelfSlug !== null) { - $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug); - $this->checkOwnablePermission('bookshelf-update', $bookshelf); - - $shelfBooks = $this->entityRepo->getBookshelfChildren($bookshelf); - $shelfBookIds = $shelfBooks->pluck('id'); - } else { - $bookshelf = null; - } - $this->checkPermission('book-create-all'); $this->validate($request, [ 'name' => 'required|string|max:255', '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()); Activity::add($book, 'book_create', $book->id); if ($bookshelf) { - $shelfBookIds = $shelfBookIds->toArray(); - array_unshift($shelfBookIds, $book->id); - - $shelfBookIds = implode(',', $shelfBookIds); - - $this->entityRepo->updateShelfBooks($bookshelf, $shelfBookIds); + $this->entityRepo->appendBookToShelf($bookshelf, $book); Activity::add($bookshelf, 'bookshelf_update'); - - return redirect($bookshelf->getUrl()); } return redirect($book->getUrl()); diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index c2c15d72f..8a3aeb022 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -74,6 +74,7 @@ return [ 'shelves_create' => 'Create New Shelf', 'shelves_popular' => 'Popular Shelves', 'shelves_new' => 'New Shelves', + 'shelves_new_action' => 'New Shelf', 'shelves_popular_empty' => 'The most popular shelves will appear here.', 'shelves_new_empty' => 'The most recently created shelves will appear here.', 'shelves_save' => 'Save Shelf', @@ -104,6 +105,7 @@ return [ 'books_popular' => 'Popular Books', 'books_recent' => 'Recent Books', 'books_new' => 'New Books', + 'books_new_action' => 'New Book', 'books_popular_empty' => 'The most popular books will appear here.', 'books_new_empty' => 'The most recently created books will appear here.', 'books_create' => 'Create New Book', diff --git a/resources/views/shelves/index.blade.php b/resources/views/shelves/index.blade.php index 76f26c694..8cf959b1e 100644 --- a/resources/views/shelves/index.blade.php +++ b/resources/views/shelves/index.blade.php @@ -12,7 +12,7 @@ @if($currentUser->can('bookshelf-create-all')) @icon('add') - {{ trans('entities.shelves_create') }} + {{ trans('entities.shelves_new_action') }} @endif @include('partials.view-toggle', ['view' => $view, 'type' => 'shelf']) diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php index a57abecb3..3a9d59951 100644 --- a/resources/views/shelves/show.blade.php +++ b/resources/views/shelves/show.blade.php @@ -23,8 +23,8 @@

{{ trans('entities.shelves_empty_contents') }}

- @if($currentUser->can('book-create-all')) - + @if(userCan('book-create-all') && userCan('bookshelf-update', $shelf)) + @icon('add') {{ trans('entities.books_create') }} @@ -80,13 +80,15 @@
{{ trans('common.actions') }}
- @if($currentUser->can('book-create-all')) + @if(userCan('book-create-all') && userCan('bookshelf-update', $shelf)) @icon('add') - {{ trans('entities.books_create') }} + {{ trans('entities.books_new_action') }} @endif +
+ @if(userCan('bookshelf-update', $shelf)) @icon('edit') diff --git a/routes/web.php b/routes/web.php index 831d54c85..d1a8b7969 100644 --- a/routes/web.php +++ b/routes/web.php @@ -26,8 +26,9 @@ Route::group(['middleware' => 'auth'], function () { Route::get('/{slug}/permissions', 'BookshelfController@showPermissions'); Route::put('/{slug}/permissions', 'BookshelfController@permissions'); Route::post('/{slug}/copy-permissions', 'BookshelfController@copyPermissions'); - Route::get('/{slug}/create-book', 'BookController@create'); - Route::post('/{slug}/create-book', 'BookController@store'); + + Route::get('/{shelfSlug}/create-book', 'BookController@create'); + Route::post('/{shelfSlug}/create-book', 'BookController@store'); }); Route::get('/create-book', 'BookController@create'); diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index e49c24739..158fb5ca1 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -48,7 +48,7 @@ class BookShelfTest extends TestCase public function test_shelves_page_contains_create_link() { $resp = $this->asEditor()->get('/shelves'); - $resp->assertElementContains('a', 'Create New Shelf'); + $resp->assertElementContains('a', 'New Shelf'); } public function test_shelves_create() @@ -103,7 +103,7 @@ class BookShelfTest extends TestCase $resp->assertSee($shelf->getUrl('/edit')); $resp->assertSee($shelf->getUrl('/permissions')); $resp->assertSee($shelf->getUrl('/delete')); - $resp->assertElementContains('a', 'Create New Book'); + $resp->assertElementContains('a', 'New Book'); $resp->assertElementContains('a', 'Edit'); $resp->assertElementContains('a', 'Permissions'); $resp->assertElementContains('a', 'Delete'); @@ -164,9 +164,15 @@ class BookShelfTest extends TestCase '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); } diff --git a/tests/Permissions/RolesTest.php b/tests/Permissions/RolesTest.php index 423db1bf0..5bbdcf0bb 100644 --- a/tests/Permissions/RolesTest.php +++ b/tests/Permissions/RolesTest.php @@ -215,7 +215,7 @@ class RolesTest extends BrowserKitTest $this->checkAccessPermission('bookshelf-create-all', [ '/create-shelf' ], [ - '/shelves' => 'Create New Shelf' + '/shelves' => 'New Shelf' ]); $this->visit('/create-shelf')