diff --git a/app/Bookshelf.php b/app/Bookshelf.php index 1e33e31f6..ce2acbf0c 100644 --- a/app/Bookshelf.php +++ b/app/Bookshelf.php @@ -11,11 +11,12 @@ class Bookshelf extends Entity /** * Get the books in this shelf. + * Should not be used directly since does not take into account permissions. * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function books() { - return $this->belongsToMany(Book::class, 'bookshelves_books', 'bookshelf_id', 'book_id'); + return $this->belongsToMany(Book::class, 'bookshelves_books', 'bookshelf_id', 'book_id')->orderBy('order', 'asc'); } /** diff --git a/app/Entity.php b/app/Entity.php index 5d4449f2b..fb1c6d48b 100644 --- a/app/Entity.php +++ b/app/Entity.php @@ -152,7 +152,7 @@ class Entity extends Ownable */ public static function getEntityInstance($type) { - $types = ['Page', 'Book', 'Chapter']; + $types = ['Page', 'Book', 'Chapter', 'Bookshelf']; $className = str_replace([' ', '-', '_'], '', ucwords($type)); if (!in_array($className, $types)) { return null; diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php index a1c56f29a..02b6299ce 100644 --- a/app/Http/Controllers/BookshelfController.php +++ b/app/Http/Controllers/BookshelfController.php @@ -2,6 +2,7 @@ use Activity; use BookStack\Book; +use BookStack\Bookshelf; use BookStack\Repos\EntityRepo; use BookStack\Repos\UserRepo; use BookStack\Services\ExportService; @@ -41,6 +42,7 @@ class BookshelfController extends Controller $popular = $this->entityRepo->getPopular('bookshelf', 4, 0); $new = $this->entityRepo->getRecentlyCreated('bookshelf', 4, 0); $shelvesViewType = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid')); + $this->setPageTitle(trans('entities.shelves')); return view('shelves/index', [ 'shelves' => $shelves, @@ -58,13 +60,13 @@ class BookshelfController extends Controller public function create() { $this->checkPermission('bookshelf-create-all'); - $this->setPageTitle(trans('entities.shelves_create')); $books = $this->entityRepo->getAll('book', false, 'update'); + $this->setPageTitle(trans('entities.shelves_create')); return view('shelves/create', ['books' => $books]); } /** - * Store a newly created book in storage. + * Store a newly created bookshelf in storage. * @param Request $request * @return Response */ @@ -83,184 +85,110 @@ class BookshelfController extends Controller return redirect($bookshelf->getUrl()); } -// -// /** -// * Display the specified book. -// * @param $slug -// * @return Response -// */ -// public function show($slug) -// { -// $book = $this->entityRepo->getBySlug('book', $slug); -// $this->checkOwnablePermission('book-view', $book); -// $bookChildren = $this->entityRepo->getBookChildren($book); -// Views::add($book); -// $this->setPageTitle($book->getShortName()); -// return view('books/show', [ -// 'book' => $book, -// 'current' => $book, -// 'bookChildren' => $bookChildren, -// 'activity' => Activity::entityActivity($book, 20, 0) -// ]); -// } -// -// /** -// * Show the form for editing the specified book. -// * @param $slug -// * @return Response -// */ -// public function edit($slug) -// { -// $book = $this->entityRepo->getBySlug('book', $slug); -// $this->checkOwnablePermission('book-update', $book); -// $this->setPageTitle(trans('entities.books_edit_named', ['bookName'=>$book->getShortName()])); -// return view('books/edit', ['book' => $book, 'current' => $book]); -// } -// -// /** -// * Update the specified book in storage. -// * @param Request $request -// * @param $slug -// * @return Response -// */ -// public function update(Request $request, $slug) -// { -// $book = $this->entityRepo->getBySlug('book', $slug); -// $this->checkOwnablePermission('book-update', $book); -// $this->validate($request, [ -// 'name' => 'required|string|max:255', -// 'description' => 'string|max:1000' -// ]); -// $book = $this->entityRepo->updateFromInput('book', $book, $request->all()); -// Activity::add($book, 'book_update', $book->id); -// return redirect($book->getUrl()); -// } -// -// /** -// * Shows the page to confirm deletion -// * @param $bookSlug -// * @return \Illuminate\View\View -// */ -// public function showDelete($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $this->checkOwnablePermission('book-delete', $book); -// $this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()])); -// return view('books/delete', ['book' => $book, 'current' => $book]); -// } -// -// /** -// * Shows the view which allows pages to be re-ordered and sorted. -// * @param string $bookSlug -// * @return \Illuminate\View\View -// */ -// public function sort($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $this->checkOwnablePermission('book-update', $book); -// $bookChildren = $this->entityRepo->getBookChildren($book, true); -// $books = $this->entityRepo->getAll('book', false, 'update'); -// $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()])); -// return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]); -// } -// -// /** -// * Shows the sort box for a single book. -// * Used via AJAX when loading in extra books to a sort. -// * @param $bookSlug -// * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View -// */ -// public function getSortItem($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $bookChildren = $this->entityRepo->getBookChildren($book); -// return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]); -// } -// -// /** -// * Saves an array of sort mapping to pages and chapters. -// * @param string $bookSlug -// * @param Request $request -// * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector -// */ -// public function saveSort($bookSlug, Request $request) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $this->checkOwnablePermission('book-update', $book); -// -// // Return if no map sent -// if (!$request->filled('sort-tree')) { -// return redirect($book->getUrl()); -// } -// -// // Sort pages and chapters -// $sortMap = collect(json_decode($request->get('sort-tree'))); -// $bookIdsInvolved = collect([$book->id]); -// -// // Load models into map -// $sortMap->each(function ($mapItem) use ($bookIdsInvolved) { -// $mapItem->type = ($mapItem->type === 'page' ? 'page' : 'chapter'); -// $mapItem->model = $this->entityRepo->getById($mapItem->type, $mapItem->id); -// // Store source and target books -// $bookIdsInvolved->push(intval($mapItem->model->book_id)); -// $bookIdsInvolved->push(intval($mapItem->book)); -// }); -// -// // Get the books involved in the sort -// $bookIdsInvolved = $bookIdsInvolved->unique()->toArray(); -// $booksInvolved = $this->entityRepo->book->newQuery()->whereIn('id', $bookIdsInvolved)->get(); -// // Throw permission error if invalid ids or inaccessible books given. -// if (count($bookIdsInvolved) !== count($booksInvolved)) { -// $this->showPermissionError(); -// } -// // Check permissions of involved books -// $booksInvolved->each(function (Book $book) { -// $this->checkOwnablePermission('book-update', $book); -// }); -// -// // Perform the sort -// $sortMap->each(function ($mapItem) { -// $model = $mapItem->model; -// -// $priorityChanged = intval($model->priority) !== intval($mapItem->sort); -// $bookChanged = intval($model->book_id) !== intval($mapItem->book); -// $chapterChanged = ($mapItem->type === 'page') && intval($model->chapter_id) !== $mapItem->parentChapter; -// -// if ($bookChanged) { -// $this->entityRepo->changeBook($mapItem->type, $mapItem->book, $model); -// } -// if ($chapterChanged) { -// $model->chapter_id = intval($mapItem->parentChapter); -// $model->save(); -// } -// if ($priorityChanged) { -// $model->priority = intval($mapItem->sort); -// $model->save(); -// } -// }); -// -// // Rebuild permissions and add activity for involved books. -// $booksInvolved->each(function (Book $book) { -// $this->entityRepo->buildJointPermissionsForBook($book); -// Activity::add($book, 'book_sort', $book->id); -// }); -// -// return redirect($book->getUrl()); -// } -// -// /** -// * Remove the specified book from storage. -// * @param $bookSlug -// * @return Response -// */ -// public function destroy($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $this->checkOwnablePermission('book-delete', $book); -// Activity::addMessage('book_delete', 0, $book->name); -// $this->entityRepo->destroyBook($book); -// return redirect('/books'); -// } + + /** + * Display the specified bookshelf. + * @param String $slug + * @return Response + * @throws \BookStack\Exceptions\NotFoundException + */ + public function show(string $slug) + { + $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */ + $this->checkOwnablePermission('book-view', $bookshelf); + + $books = $this->entityRepo->getBookshelfChildren($bookshelf); + Views::add($bookshelf); + + $this->setPageTitle($bookshelf->getShortName()); + return view('shelves/show', [ + 'shelf' => $bookshelf, + 'books' => $books, + 'activity' => Activity::entityActivity($bookshelf, 20, 0) + ]); + } + + /** + * Show the form for editing the specified bookshelf. + * @param $slug + * @return Response + * @throws \BookStack\Exceptions\NotFoundException + */ + public function edit(string $slug) + { + $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */ + $this->checkOwnablePermission('bookshelf-update', $bookshelf); + + $shelfBooks = $this->entityRepo->getBookshelfChildren($bookshelf); + $shelfBookIds = $shelfBooks->pluck('id'); + $books = $this->entityRepo->getAll('book', false, 'update'); + $books = $books->filter(function ($book) use ($shelfBookIds) { + return !$shelfBookIds->contains($book->id); + }); + + $this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $bookshelf->getShortName()])); + return view('shelves/edit', [ + 'shelf' => $bookshelf, + 'books' => $books, + 'shelfBooks' => $shelfBooks, + ]); + } + + + /** + * Update the specified bookshelf in storage. + * @param Request $request + * @param string $slug + * @return Response + * @throws \BookStack\Exceptions\NotFoundException + */ + public function update(Request $request, string $slug) + { + $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */ + $this->checkOwnablePermission('bookshelf-update', $shelf); + $this->validate($request, [ + 'name' => 'required|string|max:255', + 'description' => 'string|max:1000', + ]); + + $shelf = $this->entityRepo->updateFromInput('bookshelf', $shelf, $request->all()); + $this->entityRepo->updateShelfBooks($shelf, $request->get('books', '')); + Activity::add($shelf, 'bookshelf_update'); + + return redirect($shelf->getUrl()); + } + + + /** + * Shows the page to confirm deletion + * @param $slug + * @return \Illuminate\View\View + * @throws \BookStack\Exceptions\NotFoundException + */ + public function showDelete(string $slug) + { + $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */ + $this->checkOwnablePermission('bookshelf-delete', $bookshelf); + + $this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $bookshelf->getShortName()])); + return view('shelves/delete', ['shelf' => $bookshelf]); + } + + /** + * Remove the specified bookshelf from storage. + * @param string $slug + * @return Response + * @throws \BookStack\Exceptions\NotFoundException + * @throws \Throwable + */ + public function destroy(string $slug) + { + $bookshelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */ + $this->checkOwnablePermission('bookshelf-delete', $bookshelf); + Activity::addMessage('bookshelf_delete', 0, $bookshelf->name); + $this->entityRepo->destroyBookshelf($bookshelf); + return redirect('/shelves'); + } // // /** // * Show the Restrictions view. @@ -293,49 +221,5 @@ class BookshelfController extends Controller // session()->flash('success', trans('entities.books_permissions_updated')); // return redirect($book->getUrl()); // } -// -// /** -// * Export a book as a PDF file. -// * @param string $bookSlug -// * @return mixed -// */ -// public function exportPdf($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $pdfContent = $this->exportService->bookToPdf($book); -// return response()->make($pdfContent, 200, [ -// 'Content-Type' => 'application/octet-stream', -// 'Content-Disposition' => 'attachment; filename="' . $bookSlug . '.pdf' -// ]); -// } -// -// /** -// * Export a book as a contained HTML file. -// * @param string $bookSlug -// * @return mixed -// */ -// public function exportHtml($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $htmlContent = $this->exportService->bookToContainedHtml($book); -// return response()->make($htmlContent, 200, [ -// 'Content-Type' => 'application/octet-stream', -// 'Content-Disposition' => 'attachment; filename="' . $bookSlug . '.html' -// ]); -// } -// -// /** -// * Export a book as a plain text file. -// * @param $bookSlug -// * @return mixed -// */ -// public function exportPlainText($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $htmlContent = $this->exportService->bookToPlainText($book); -// return response()->make($htmlContent, 200, [ -// 'Content-Type' => 'application/octet-stream', -// 'Content-Disposition' => 'attachment; filename="' . $bookSlug . '.txt' -// ]); -// } + } diff --git a/app/Repos/EntityRepo.php b/app/Repos/EntityRepo.php index ea7fc4882..ab4b7cc04 100644 --- a/app/Repos/EntityRepo.php +++ b/app/Repos/EntityRepo.php @@ -340,6 +340,17 @@ class EntityRepo ->skip($count * $page)->take($count)->get(); } + /** + * Get the child items for a chapter sorted by priority but + * with draft items floated to the top. + * @param Bookshelf $bookshelf + * @return \Illuminate\Database\Eloquent\Collection|static[] + */ + public function getBookshelfChildren(Bookshelf $bookshelf) + { + return $this->permissionService->enforceEntityRestrictions('book', $bookshelf->books())->get(); + } + /** * Get all child objects of a book. * Returns a sorted collection of Pages and Chapters. @@ -551,12 +562,17 @@ class EntityRepo public function updateShelfBooks(Bookshelf $shelf, string $books) { $ids = explode(',', $books); - if (count($ids) === 0) { - return; + + // Check books exist and match ordering + $bookIds = $this->entityQuery('book')->whereIn('id', $ids)->get(['id'])->pluck('id'); + $syncData = []; + foreach ($ids as $index => $id) { + if ($bookIds->contains($id)) { + $syncData[$id] = ['order' => $index]; + } } - $bookIds = $this->entityQuery('book')->whereIn('id', $ids)->get(['id'])->pluck('id'); - $shelf->books()->sync($bookIds); + $shelf->books()->sync($syncData); } /** @@ -1180,6 +1196,17 @@ class EntityRepo $this->permissionService->buildJointPermissionsForEntity($book); } + /** + * Destroy a bookshelf instance + * @param Bookshelf $shelf + * @throws \Throwable + */ + public function destroyBookshelf(Bookshelf $shelf) + { + $this->destroyEntityCommonRelations($shelf); + $shelf->delete(); + } + /** * Destroy the provided book and all its child entities. * @param Book $book @@ -1194,11 +1221,7 @@ class EntityRepo foreach ($book->chapters as $chapter) { $this->destroyChapter($chapter); } - \Activity::removeEntity($book); - $book->views()->delete(); - $book->permissions()->delete(); - $this->permissionService->deleteJointPermissionsForEntity($book); - $this->searchService->deleteEntityTerms($book); + $this->destroyEntityCommonRelations($book); $book->delete(); } @@ -1215,11 +1238,7 @@ class EntityRepo $page->save(); } } - \Activity::removeEntity($chapter); - $chapter->views()->delete(); - $chapter->permissions()->delete(); - $this->permissionService->deleteJointPermissionsForEntity($chapter); - $this->searchService->deleteEntityTerms($chapter); + $this->destroyEntityCommonRelations($chapter); $chapter->delete(); } @@ -1231,13 +1250,7 @@ class EntityRepo */ public function destroyPage(Page $page) { - \Activity::removeEntity($page); - $page->views()->delete(); - $page->tags()->delete(); - $page->revisions()->delete(); - $page->permissions()->delete(); - $this->permissionService->deleteJointPermissionsForEntity($page); - $this->searchService->deleteEntityTerms($page); + $this->destroyEntityCommonRelations($page); // Check if set as custom homepage $customHome = setting('app-homepage', '0:'); @@ -1253,4 +1266,20 @@ class EntityRepo $page->delete(); } + + /** + * Destroy or handle the common relations connected to an entity. + * @param Entity $entity + * @throws \Throwable + */ + protected function destroyEntityCommonRelations(Entity $entity) + { + \Activity::removeEntity($entity); + $entity->views()->delete(); + $entity->permissions()->delete(); + $entity->tags()->delete(); + $entity->comments()->delete(); + $this->permissionService->deleteJointPermissionsForEntity($entity); + $this->searchService->deleteEntityTerms($entity); + } } diff --git a/database/migrations/2018_08_04_115700_create_bookshelves_table.php b/database/migrations/2018_08_04_115700_create_bookshelves_table.php index c7840e1a1..e92b0edef 100644 --- a/database/migrations/2018_08_04_115700_create_bookshelves_table.php +++ b/database/migrations/2018_08_04_115700_create_bookshelves_table.php @@ -33,6 +33,7 @@ class CreateBookshelvesTable extends Migration Schema::create('bookshelves_books', function (Blueprint $table) { $table->integer('bookshelf_id')->unsigned(); $table->integer('book_id')->unsigned(); + $table->integer('order')->unsigned(); $table->foreign('bookshelf_id')->references('id')->on('bookshelves') ->onUpdate('cascade')->onDelete('cascade'); @@ -86,7 +87,15 @@ class CreateBookshelvesTable extends Migration DB::table('role_permissions')->whereIn('id', $permissionIds)->delete(); // Drop shelves table - Schema::dropIfExists('bookshelves'); Schema::dropIfExists('bookshelves_books'); + Schema::dropIfExists('bookshelves'); + + // Drop related polymorphic items + DB::table('activities')->where('entity_type', '=', 'BookStack\Bookshelf')->delete(); + DB::table('views')->where('viewable_type', '=', 'BookStack\Bookshelf')->delete(); + DB::table('entity_permissions')->where('restrictable_type', '=', 'BookStack\Bookshelf')->delete(); + DB::table('tags')->where('entity_type', '=', 'BookStack\Bookshelf')->delete(); + DB::table('search_terms')->where('entity_type', '=', 'BookStack\Bookshelf')->delete(); + DB::table('comments')->where('entity_type', '=', 'BookStack\Bookshelf')->delete(); } } diff --git a/resources/lang/en/activities.php b/resources/lang/en/activities.php index 187fe1e53..153ae33f0 100644 --- a/resources/lang/en/activities.php +++ b/resources/lang/en/activities.php @@ -37,6 +37,14 @@ return [ 'book_sort' => 'sorted book', 'book_sort_notification' => 'Book Successfully Re-sorted', + // Bookshelves + 'bookshelf_create' => 'created Bookshelf', + 'bookshelf_create_notification' => 'Bookshelf Successfully Created', + 'bookshelf_update' => 'updated bookshelf', + 'bookshelf_update_notification' => 'Bookshelf Successfully Updated', + 'bookshelf_delete' => 'deleted bookshelf', + 'bookshelf_delete_notification' => 'Bookshelf Successfully Deleted', + // Other 'commented_on' => 'commented on', ]; diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index c744c5557..8d1363240 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -79,6 +79,14 @@ return [ 'shelves_books' => 'Books on this shelf', 'shelves_add_books' => 'Add books to this shelf', 'shelves_drag_books' => 'Drag books here to add them to this shelf', + 'shelves_empty_contents' => 'This shelf has no books assigned to it', + 'shelves_edit_and_assign' => 'Edit shelf to assign books', + 'shelves_edit_named' => 'Edit Bookshelf :name', + 'shelves_edit' => 'Edit Bookshelf', + 'shelves_delete' => 'Delete Bookshelf', + 'shelves_delete_named' => 'Delete Bookshelf :name', + 'shelves_delete_explain' => "This will delete the bookshelf with the name ':name'. Contained books will not be deleted.", + 'shelves_delete_confirmation' => 'Are you sure you want to delete this bookshelf?', /** * Books diff --git a/resources/views/shelves/_breadcrumbs.blade.php b/resources/views/shelves/_breadcrumbs.blade.php index e4ecc36c6..91b4252ef 100644 --- a/resources/views/shelves/_breadcrumbs.blade.php +++ b/resources/views/shelves/_breadcrumbs.blade.php @@ -1,3 +1,3 @@ <div class="breadcrumbs"> - <a href="{{$book->getUrl()}}" class="text-book text-button">@icon('book'){{ $book->getShortName() }}</a> + <a href="{{$shelf->getUrl()}}" class="text-bookshelf text-button">@icon('bookshelf'){{ $shelf->getShortName() }}</a> </div> \ No newline at end of file diff --git a/resources/views/shelves/create.blade.php b/resources/views/shelves/create.blade.php index aaff08974..32e40a4ae 100644 --- a/resources/views/shelves/create.blade.php +++ b/resources/views/shelves/create.blade.php @@ -18,7 +18,7 @@ <h3>@icon('add') {{ trans('entities.shelves_create') }}</h3> <div class="body"> <form action="{{ baseUrl("/shelves") }}" method="POST" enctype="multipart/form-data"> - @include('shelves/form') + @include('shelves/form', ['shelf' => null, 'books' => $books]) </form> </div> </div> diff --git a/resources/views/shelves/delete.blade.php b/resources/views/shelves/delete.blade.php index 0ac98e895..f3ad62456 100644 --- a/resources/views/shelves/delete.blade.php +++ b/resources/views/shelves/delete.blade.php @@ -2,7 +2,7 @@ @section('toolbar') <div class="col-sm-12 faded"> - @include('books._breadcrumbs', ['book' => $book]) + @include('shelves._breadcrumbs', ['shelf' => $shelf]) </div> @stop @@ -11,20 +11,20 @@ <div class="container small"> <p> </p> <div class="card"> - <h3>@icon('delete') {{ trans('entities.books_delete') }}</h3> + <h3>@icon('delete') {{ trans('entities.shelves_delete') }}</h3> <div class="body"> - <p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p> - <p class="text-neg">{{ trans('entities.books_delete_confirmation') }}</p> + <p>{{ trans('entities.shelves_delete_explain', ['name' => $shelf->name]) }}</p> + <p class="text-neg">{{ trans('entities.shelves_delete_confirmation') }}</p> - <form action="{{$book->getUrl()}}" method="POST"> + <form action="{{ $shelf->getUrl() }}" method="POST"> {!! csrf_field() !!} <input type="hidden" name="_method" value="DELETE"> - <a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a> - <button type="submit" class="button neg">{{ trans('common.confirm') }}</button> + + <a href="{{ $shelf->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a> + <button type="submit" class="button">{{ trans('common.confirm') }}</button> </form> </div> </div> - </div> @stop \ No newline at end of file diff --git a/resources/views/shelves/edit.blade.php b/resources/views/shelves/edit.blade.php index cb1ffc461..ab88051e5 100644 --- a/resources/views/shelves/edit.blade.php +++ b/resources/views/shelves/edit.blade.php @@ -2,7 +2,7 @@ @section('toolbar') <div class="col-sm-12 faded"> - @include('books._breadcrumbs', ['book' => $book]) + @include('shelves._breadcrumbs', ['shelf' => $shelf]) </div> @stop @@ -11,11 +11,11 @@ <div class="container small"> <p> </p> <div class="card"> - <h3>@icon('edit') {{ trans('entities.books_edit') }}</h3> + <h3>@icon('edit') {{ trans('entities.shelves_edit') }}</h3> <div class="body"> - <form action="{{ $book->getUrl() }}" method="POST"> + <form action="{{ $shelf->getUrl() }}" method="POST"> <input type="hidden" name="_method" value="PUT"> - @include('books/form', ['model' => $book]) + @include('shelves/form', ['model' => $shelf]) </form> </div> </div> diff --git a/resources/views/shelves/form.blade.php b/resources/views/shelves/form.blade.php index 142e5c69e..fb6fee115 100644 --- a/resources/views/shelves/form.blade.php +++ b/resources/views/shelves/form.blade.php @@ -23,8 +23,8 @@ <div class="scroll-box-item scroll-box-placeholder" style="display: none;"> <a href="#" class="text-muted">@icon('book') ...</a> </div> - @if (isset($shelf) && count($shelf->books) > 0) - @foreach ($shelf->books as $book) + @if (isset($shelfBooks) && count($shelfBooks) > 0) + @foreach ($shelfBooks as $book) <div data-id="{{ $book->id }}" class="scroll-box-item"> <a href="{{ $book->getUrl() }}" class="text-book">@icon('book'){{ $book->name }}</a> </div> diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php index e5845b495..2aae2c6ff 100644 --- a/resources/views/shelves/show.blade.php +++ b/resources/views/shelves/show.blade.php @@ -2,37 +2,22 @@ @section('toolbar') <div class="col-sm-6 col-xs-1 faded"> - @include('books._breadcrumbs', ['book' => $book]) + @include('shelves._breadcrumbs', ['shelf' => $shelf]) </div> <div class="col-sm-6 col-xs-11"> <div class="action-buttons faded"> - <span dropdown class="dropdown-container"> - <div dropdown-toggle class="text-button text-primary">@icon('export'){{ trans('entities.export') }}</div> - <ul class="wide"> - <li><a href="{{ $book->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li> - <li><a href="{{ $book->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li> - <li><a href="{{ $book->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li> - </ul> - </span> - @if(userCan('page-create', $book)) - <a href="{{ $book->getUrl('/create-page') }}" class="text-pos text-button">@icon('add'){{ trans('entities.pages_new') }}</a> + @if(userCan('bookshelf-update', $shelf)) + <a href="{{ $shelf->getUrl('/edit') }}" class="text-button text-primary">@icon('edit'){{ trans('common.edit') }}</a> @endif - @if(userCan('chapter-create', $book)) - <a href="{{ $book->getUrl('/create-chapter') }}" class="text-pos text-button">@icon('add'){{ trans('entities.chapters_new') }}</a> - @endif - @if(userCan('book-update', $book) || userCan('restrictions-manage', $book) || userCan('book-delete', $book)) + @if(userCan('restrictions-manage', $shelf) || userCan('bookshelf-delete', $shelf)) <div dropdown class="dropdown-container"> <a dropdown-toggle class="text-primary text-button">@icon('more'){{ trans('common.more') }}</a> <ul> - @if(userCan('book-update', $book)) - <li><a href="{{ $book->getUrl('/edit') }}" class="text-primary">@icon('edit'){{ trans('common.edit') }}</a></li> - <li><a href="{{ $book->getUrl('/sort') }}" class="text-primary">@icon('sort'){{ trans('common.sort') }}</a></li> + @if(userCan('restrictions-manage', $shelf)) + <li><a href="{{ $shelf->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li> @endif - @if(userCan('restrictions-manage', $book)) - <li><a href="{{ $book->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li> - @endif - @if(userCan('book-delete', $book)) - <li><a href="{{ $book->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li> + @if(userCan('bookshelf-delete', $shelf)) + <li><a href="{{ $shelf->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li> @endif </ul> </div> @@ -43,32 +28,22 @@ @section('sidebar') - @if($book->tags->count() > 0) + @if($shelf->tags->count() > 0) <section> - @include('components.tag-list', ['entity' => $book]) + @include('components.tag-list', ['entity' => $shelf]) </section> @endif - <div class="card"> - <div class="body"> - <form v-on:submit.prevent="searchBook" class="search-box"> - <input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}"> - <button type="submit">@icon('search')</button> - <button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button">@icon('close')</button> - </form> - </div> - </div> - <div class="card entity-details"> <h3>@icon('info') {{ trans('common.details') }}</h3> <div class="body text-small text-muted blended-links"> - @include('partials.entity-meta', ['entity' => $book]) - @if($book->restricted) + @include('partials.entity-meta', ['entity' => $shelf]) + @if($shelf->restricted) <div class="active-restriction"> - @if(userCan('restrictions-manage', $book)) - <a href="{{ $book->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.books_permissions_active') }}</a> + @if(userCan('restrictions-manage', $shelf)) + <a href="{{ $shelf->getUrl('/permissions') }}">@icon('lock'){{ trans('entities.shelves_permissions_active') }}</a> @else - @icon('lock'){{ trans('entities.books_permissions_active') }} + @icon('lock'){{ trans('entities.shelves_permissions_active') }} @endif </div> @endif @@ -83,53 +58,31 @@ @endif @stop -@section('container-attrs') - id="entity-dashboard" - entity-id="{{ $book->id }}" - entity-type="book" -@stop - @section('body') <div class="container small nopad"> - <h1 class="break-text" v-pre>{{$book->name}}</h1> - <div class="book-content" v-show="!searching"> - <p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p> - @if(count($bookChildren) > 0) - <div class="page-list" v-pre> + <h1 class="break-text">{{$shelf->name}}</h1> + <div class="book-content"> + <p class="text-muted">{!! nl2br(e($shelf->description)) !!}</p> + @if(count($books) > 0) + <div class="page-list"> <hr> - @foreach($bookChildren as $childElement) - @if($childElement->isA('chapter')) - @include('chapters/list-item', ['chapter' => $childElement]) - @else - @include('pages/list-item', ['page' => $childElement]) - @endif + @foreach($books as $book) + @include('books/list-item', ['book' => $book]) <hr> @endforeach </div> @else - <div class="well"> - <p class="text-muted italic">{{ trans('entities.books_empty_contents') }}</p> - @if(userCan('page-create', $book)) - <a href="{{ $book->getUrl('/create-page') }}" class="button outline page">@icon('page'){{ trans('entities.books_empty_create_page') }}</a> - @endif - @if(userCan('page-create', $book) && userCan('chapter-create', $book)) - <em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em> - @endif - @if(userCan('chapter-create', $book)) - <a href="{{ $book->getUrl('/create-chapter') }}" class="button outline chapter">@icon('chapter'){{ trans('entities.books_empty_add_chapter') }}</a> - @endif - </div> + <p> + <hr> + <span class="text-muted italic">{{ trans('entities.shelves_empty_contents') }}</span> + @if(userCan('bookshelf-create', $shelf)) + <br> + <a href="{{ $shelf->getUrl('/edit') }}" class="button outline bookshelf">{{ trans('entities.shelves_edit_and_assign') }}</a> + @endif + </p> @endif - </div> - <div class="search-results" v-cloak v-show="searching"> - <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small">@icon('close'){{ trans('entities.search_clear') }}</a></h3> - <div v-if="!searchResults"> - @include('partials/loading-icon') - </div> - <div v-html="searchResults"></div> - </div> </div> @stop diff --git a/routes/web.php b/routes/web.php index 7eae4a3fa..be0b2da6e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -19,6 +19,11 @@ Route::group(['middleware' => 'auth'], function () { Route::group(['prefix' => 'shelves'], function() { Route::get('/', 'BookshelfController@index'); Route::post('/', 'BookshelfController@store'); + Route::get('/{slug}/edit', 'BookshelfController@edit'); + Route::get('/{slug}/delete', 'BookshelfController@showDelete'); + Route::get('/{slug}', 'BookshelfController@show'); + Route::put('/{slug}', 'BookshelfController@update'); + Route::delete('/{slug}', 'BookshelfController@destroy'); }); Route::get('/create-book', 'BookController@create');