X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/b89411c108f08248215421a34bbf66bdf072d049..refs/pull/2227/head:/app/Http/Controllers/BookshelfController.php diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php index a1c56f29a..f2cc11c7b 100644 --- a/app/Http/Controllers/BookshelfController.php +++ b/app/Http/Controllers/BookshelfController.php @@ -1,72 +1,83 @@ entityRepo = $entityRepo; - $this->userRepo = $userRepo; - $this->exportService = $exportService; + $this->bookshelfRepo = $bookshelfRepo; + $this->entityContextManager = $entityContextManager; + $this->imageRepo = $imageRepo; parent::__construct(); } /** * Display a listing of the book. - * @return Response */ public function index() { - $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18); - $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('bookshelf', 4, 0) : false; - $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')); + $view = setting()->getForCurrentUser('bookshelves_view_type', config('app.views.bookshelves', 'grid')); + $sort = setting()->getForCurrentUser('bookshelves_sort', 'name'); + $order = setting()->getForCurrentUser('bookshelves_sort_order', 'asc'); + $sortOptions = [ + 'name' => trans('common.sort_name'), + 'created_at' => trans('common.sort_created_at'), + 'updated_at' => trans('common.sort_updated_at'), + ]; + + $shelves = $this->bookshelfRepo->getAllPaginated(18, $sort, $order); + $recents = $this->isSignedIn() ? $this->bookshelfRepo->getRecentlyViewed(4) : false; + $popular = $this->bookshelfRepo->getPopular(4); + $new = $this->bookshelfRepo->getRecentlyCreated(4); + + $this->entityContextManager->clearShelfContext(); $this->setPageTitle(trans('entities.shelves')); - return view('shelves/index', [ + return view('shelves.index', [ 'shelves' => $shelves, 'recents' => $recents, 'popular' => $popular, 'new' => $new, - 'shelvesViewType' => $shelvesViewType + 'view' => $view, + 'sort' => $sort, + 'order' => $order, + 'sortOptions' => $sortOptions, ]); } /** * Show the form for creating a new bookshelf. - * @return Response */ public function create() { $this->checkPermission('bookshelf-create-all'); + $books = Book::hasPermission('update')->get(); $this->setPageTitle(trans('entities.shelves_create')); - $books = $this->entityRepo->getAll('book', false, 'update'); - return view('shelves/create', ['books' => $books]); + return view('shelves.create', ['books' => $books]); } /** - * Store a newly created book in storage. - * @param Request $request - * @return Response + * Store a newly created bookshelf in storage. + * @throws ValidationException + * @throws ImageUploadException */ public function store(Request $request) { @@ -74,268 +85,148 @@ class BookshelfController extends Controller $this->validate($request, [ 'name' => 'required|string|max:255', 'description' => 'string|max:1000', + 'image' => 'nullable|' . $this->getImageValidationRules(), + ]); + + $bookIds = explode(',', $request->get('books', '')); + $shelf = $this->bookshelfRepo->create($request->all(), $bookIds); + $this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null)); + + Activity::add($shelf, 'bookshelf_create'); + return redirect($shelf->getUrl()); + } + + /** + * Display the bookshelf of the given slug. + * @throws NotFoundException + */ + public function show(string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('book-view', $shelf); + + Views::add($shelf); + $this->entityContextManager->setShelfContext($shelf->id); + $view = setting()->getForCurrentUser('bookshelf_view_type', config('app.views.books')); + + $this->setPageTitle($shelf->getShortName()); + return view('shelves.show', [ + 'shelf' => $shelf, + 'view' => $view, + 'activity' => Activity::entityActivity($shelf, 20, 1) + ]); + } + + /** + * Show the form for editing the specified bookshelf. + */ + public function edit(string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('bookshelf-update', $shelf); + + $shelfBookIds = $shelf->books()->get(['id'])->pluck('id'); + $books = Book::hasPermission('update')->whereNotIn('id', $shelfBookIds)->get(); + + $this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()])); + return view('shelves.edit', [ + 'shelf' => $shelf, + 'books' => $books, + ]); + } + + /** + * Update the specified bookshelf in storage. + * @throws ValidationException + * @throws ImageUploadException + * @throws NotFoundException + */ + public function update(Request $request, string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('bookshelf-update', $shelf); + $this->validate($request, [ + 'name' => 'required|string|max:255', + 'description' => 'string|max:1000', + 'image' => 'nullable|' . $this->getImageValidationRules(), + ]); + + + $bookIds = explode(',', $request->get('books', '')); + $shelf = $this->bookshelfRepo->update($shelf, $request->all(), $bookIds); + $resetCover = $request->has('image_reset'); + $this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null), $resetCover); + Activity::add($shelf, 'bookshelf_update'); + + return redirect($shelf->getUrl()); + } + + /** + * Shows the page to confirm deletion + */ + public function showDelete(string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('bookshelf-delete', $shelf); + + $this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $shelf->getShortName()])); + return view('shelves.delete', ['shelf' => $shelf]); + } + + /** + * Remove the specified bookshelf from storage. + * @throws Exception + */ + public function destroy(string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('bookshelf-delete', $shelf); + + Activity::addMessage('bookshelf_delete', $shelf->name); + $this->bookshelfRepo->destroy($shelf); + + return redirect('/shelves'); + } + + /** + * Show the permissions view. + */ + public function showPermissions(string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $shelf); + + return view('shelves.permissions', [ + 'shelf' => $shelf, ]); + } - $bookshelf = $this->entityRepo->createFromInput('bookshelf', $request->all()); - $this->entityRepo->updateShelfBooks($bookshelf, $request->get('books', '')); - Activity::add($bookshelf, 'bookshelf_create'); + /** + * Set the permissions for this bookshelf. + */ + public function permissions(Request $request, string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $shelf); + + $restricted = $request->get('restricted') === 'true'; + $permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null; + $this->bookshelfRepo->updatePermissions($shelf, $restricted, $permissions); - return redirect($bookshelf->getUrl()); + $this->showSuccessNotification(trans('entities.shelves_permissions_updated')); + return redirect($shelf->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'); -// } -// -// /** -// * Show the Restrictions view. -// * @param $bookSlug -// * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View -// */ -// public function showRestrict($bookSlug) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $this->checkOwnablePermission('restrictions-manage', $book); -// $roles = $this->userRepo->getRestrictableRoles(); -// return view('books/restrictions', [ -// 'book' => $book, -// 'roles' => $roles -// ]); -// } -// -// /** -// * Set the restrictions for this book. -// * @param $bookSlug -// * @param $bookSlug -// * @param Request $request -// * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector -// */ -// public function restrict($bookSlug, Request $request) -// { -// $book = $this->entityRepo->getBySlug('book', $bookSlug); -// $this->checkOwnablePermission('restrictions-manage', $book); -// $this->entityRepo->updateEntityPermissionsFromRequest($request, $book); -// 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' -// ]); -// } + /** + * Copy the permissions of a bookshelf to the child books. + */ + public function copyPermissions(string $slug) + { + $shelf = $this->bookshelfRepo->getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $shelf); + + $updateCount = $this->bookshelfRepo->copyDownPermissions($shelf); + $this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount])); + return redirect($shelf->getUrl()); + } }