3 namespace BookStack\Entities\Controllers;
5 use BookStack\Activity\ActivityQueries;
6 use BookStack\Activity\Models\View;
7 use BookStack\Entities\Queries\BookQueries;
8 use BookStack\Entities\Queries\BookshelfQueries;
9 use BookStack\Entities\Queries\EntityQueries;
10 use BookStack\Entities\Repos\BookshelfRepo;
11 use BookStack\Entities\Tools\ShelfContext;
12 use BookStack\Exceptions\ImageUploadException;
13 use BookStack\Exceptions\NotFoundException;
14 use BookStack\Http\Controller;
15 use BookStack\Permissions\Permission;
16 use BookStack\References\ReferenceFetcher;
17 use BookStack\Util\SimpleListOptions;
19 use Illuminate\Http\Request;
20 use Illuminate\Validation\ValidationException;
22 class BookshelfController extends Controller
24 public function __construct(
25 protected BookshelfRepo $shelfRepo,
26 protected BookshelfQueries $queries,
27 protected EntityQueries $entityQueries,
28 protected BookQueries $bookQueries,
29 protected ShelfContext $shelfContext,
30 protected ReferenceFetcher $referenceFetcher,
35 * Display a listing of bookshelves.
37 public function index(Request $request)
39 $view = setting()->getForCurrentUser('bookshelves_view_type');
40 $listOptions = SimpleListOptions::fromRequest($request, 'bookshelves')->withSortOptions([
41 'name' => trans('common.sort_name'),
42 'created_at' => trans('common.sort_created_at'),
43 'updated_at' => trans('common.sort_updated_at'),
46 $shelves = $this->queries->visibleForListWithCover()
47 ->orderBy($listOptions->getSort(), $listOptions->getOrder())
49 $recents = $this->isSignedIn() ? $this->queries->recentlyViewedForCurrentUser()->get() : false;
50 $popular = $this->queries->popularForList()->get();
51 $new = $this->queries->visibleForList()
52 ->orderBy('created_at', 'desc')
56 $this->shelfContext->clearShelfContext();
57 $this->setPageTitle(trans('entities.shelves'));
59 return view('shelves.index', [
60 'shelves' => $shelves,
61 'recents' => $recents,
62 'popular' => $popular,
65 'listOptions' => $listOptions,
70 * Show the form for creating a new bookshelf.
72 public function create()
74 $this->checkPermission(Permission::BookshelfCreateAll);
75 $books = $this->bookQueries->visibleForList()->orderBy('name')->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
76 $this->setPageTitle(trans('entities.shelves_create'));
78 return view('shelves.create', ['books' => $books]);
82 * Store a newly created bookshelf in storage.
84 * @throws ValidationException
85 * @throws ImageUploadException
87 public function store(Request $request)
89 $this->checkPermission(Permission::BookshelfCreateAll);
90 $validated = $this->validate($request, [
91 'name' => ['required', 'string', 'max:255'],
92 'description_html' => ['string', 'max:2000'],
93 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
97 $bookIds = explode(',', $request->get('books', ''));
98 $shelf = $this->shelfRepo->create($validated, $bookIds);
100 return redirect($shelf->getUrl());
104 * Display the bookshelf of the given slug.
106 * @throws NotFoundException
108 public function show(Request $request, ActivityQueries $activities, string $slug)
111 $shelf = $this->queries->findVisibleBySlugOrFail($slug);
112 } catch (NotFoundException $exception) {
113 $shelf = $this->entityQueries->findVisibleByOldSlugs('bookshelf', $slug);
114 if (is_null($shelf)) {
117 return redirect($shelf->getUrl());
120 $this->checkOwnablePermission(Permission::BookshelfView, $shelf);
122 $listOptions = SimpleListOptions::fromRequest($request, 'shelf_books')->withSortOptions([
123 'default' => trans('common.sort_default'),
124 'name' => trans('common.sort_name'),
125 'created_at' => trans('common.sort_created_at'),
126 'updated_at' => trans('common.sort_updated_at'),
129 $sort = $listOptions->getSort();
131 $sortedVisibleShelfBooks = $shelf->visibleBooks()
132 ->reorder($sort === 'default' ? 'order' : $sort, $listOptions->getOrder())
137 View::incrementFor($shelf);
138 $this->shelfContext->setShelfContext($shelf->id);
139 $view = setting()->getForCurrentUser('bookshelf_view_type');
141 $this->setPageTitle($shelf->getShortName());
143 return view('shelves.show', [
145 'sortedVisibleShelfBooks' => $sortedVisibleShelfBooks,
147 'activity' => $activities->entityActivity($shelf, 20, 1),
148 'listOptions' => $listOptions,
149 'referenceCount' => $this->referenceFetcher->getReferenceCountToEntity($shelf),
154 * Show the form for editing the specified bookshelf.
156 public function edit(string $slug)
158 $shelf = $this->queries->findVisibleBySlugOrFail($slug);
159 $this->checkOwnablePermission(Permission::BookshelfUpdate, $shelf);
161 $shelfBookIds = $shelf->books()->get(['id'])->pluck('id');
162 $books = $this->bookQueries->visibleForList()
163 ->whereNotIn('id', $shelfBookIds)
165 ->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
167 $this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()]));
169 return view('shelves.edit', [
176 * Update the specified bookshelf in storage.
178 * @throws ValidationException
179 * @throws ImageUploadException
180 * @throws NotFoundException
182 public function update(Request $request, string $slug)
184 $shelf = $this->queries->findVisibleBySlugOrFail($slug);
185 $this->checkOwnablePermission(Permission::BookshelfUpdate, $shelf);
186 $validated = $this->validate($request, [
187 'name' => ['required', 'string', 'max:255'],
188 'description_html' => ['string', 'max:2000'],
189 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
193 if ($request->has('image_reset')) {
194 $validated['image'] = null;
195 } elseif (array_key_exists('image', $validated) && is_null($validated['image'])) {
196 unset($validated['image']);
199 $bookIds = explode(',', $request->get('books', ''));
200 $shelf = $this->shelfRepo->update($shelf, $validated, $bookIds);
202 return redirect($shelf->getUrl());
206 * Shows the page to confirm deletion.
208 public function showDelete(string $slug)
210 $shelf = $this->queries->findVisibleBySlugOrFail($slug);
211 $this->checkOwnablePermission(Permission::BookshelfDelete, $shelf);
213 $this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $shelf->getShortName()]));
215 return view('shelves.delete', ['shelf' => $shelf]);
219 * Remove the specified bookshelf from storage.
223 public function destroy(string $slug)
225 $shelf = $this->queries->findVisibleBySlugOrFail($slug);
226 $this->checkOwnablePermission(Permission::BookshelfDelete, $shelf);
228 $this->shelfRepo->destroy($shelf);
230 return redirect('/shelves');