]> BookStack Code Mirror - bookstack/blob - app/Entities/Controllers/BookshelfController.php
Slugs: Rolled out history lookup to other types
[bookstack] / app / Entities / Controllers / BookshelfController.php
1 <?php
2
3 namespace BookStack\Entities\Controllers;
4
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;
18 use Exception;
19 use Illuminate\Http\Request;
20 use Illuminate\Validation\ValidationException;
21
22 class BookshelfController extends Controller
23 {
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,
31     ) {
32     }
33
34     /**
35      * Display a listing of bookshelves.
36      */
37     public function index(Request $request)
38     {
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'),
44         ]);
45
46         $shelves = $this->queries->visibleForListWithCover()
47             ->orderBy($listOptions->getSort(), $listOptions->getOrder())
48             ->paginate(18);
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')
53             ->take(4)
54             ->get();
55
56         $this->shelfContext->clearShelfContext();
57         $this->setPageTitle(trans('entities.shelves'));
58
59         return view('shelves.index', [
60             'shelves'     => $shelves,
61             'recents'     => $recents,
62             'popular'     => $popular,
63             'new'         => $new,
64             'view'        => $view,
65             'listOptions' => $listOptions,
66         ]);
67     }
68
69     /**
70      * Show the form for creating a new bookshelf.
71      */
72     public function create()
73     {
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'));
77
78         return view('shelves.create', ['books' => $books]);
79     }
80
81     /**
82      * Store a newly created bookshelf in storage.
83      *
84      * @throws ValidationException
85      * @throws ImageUploadException
86      */
87     public function store(Request $request)
88     {
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()),
94             'tags'             => ['array'],
95         ]);
96
97         $bookIds = explode(',', $request->get('books', ''));
98         $shelf = $this->shelfRepo->create($validated, $bookIds);
99
100         return redirect($shelf->getUrl());
101     }
102
103     /**
104      * Display the bookshelf of the given slug.
105      *
106      * @throws NotFoundException
107      */
108     public function show(Request $request, ActivityQueries $activities, string $slug)
109     {
110         try {
111             $shelf = $this->queries->findVisibleBySlugOrFail($slug);
112         } catch (NotFoundException $exception) {
113             $shelf = $this->entityQueries->findVisibleByOldSlugs('bookshelf', $slug);
114             if (is_null($shelf)) {
115                 throw $exception;
116             }
117             return redirect($shelf->getUrl());
118         }
119
120         $this->checkOwnablePermission(Permission::BookshelfView, $shelf);
121
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'),
127         ]);
128
129         $sort = $listOptions->getSort();
130
131         $sortedVisibleShelfBooks = $shelf->visibleBooks()
132             ->reorder($sort === 'default' ? 'order' : $sort, $listOptions->getOrder())
133             ->get()
134             ->values()
135             ->all();
136
137         View::incrementFor($shelf);
138         $this->shelfContext->setShelfContext($shelf->id);
139         $view = setting()->getForCurrentUser('bookshelf_view_type');
140
141         $this->setPageTitle($shelf->getShortName());
142
143         return view('shelves.show', [
144             'shelf'                   => $shelf,
145             'sortedVisibleShelfBooks' => $sortedVisibleShelfBooks,
146             'view'                    => $view,
147             'activity'                => $activities->entityActivity($shelf, 20, 1),
148             'listOptions'             => $listOptions,
149             'referenceCount'          => $this->referenceFetcher->getReferenceCountToEntity($shelf),
150         ]);
151     }
152
153     /**
154      * Show the form for editing the specified bookshelf.
155      */
156     public function edit(string $slug)
157     {
158         $shelf = $this->queries->findVisibleBySlugOrFail($slug);
159         $this->checkOwnablePermission(Permission::BookshelfUpdate, $shelf);
160
161         $shelfBookIds = $shelf->books()->get(['id'])->pluck('id');
162         $books = $this->bookQueries->visibleForList()
163             ->whereNotIn('id', $shelfBookIds)
164             ->orderBy('name')
165             ->get(['name', 'id', 'slug', 'created_at', 'updated_at']);
166
167         $this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()]));
168
169         return view('shelves.edit', [
170             'shelf' => $shelf,
171             'books' => $books,
172         ]);
173     }
174
175     /**
176      * Update the specified bookshelf in storage.
177      *
178      * @throws ValidationException
179      * @throws ImageUploadException
180      * @throws NotFoundException
181      */
182     public function update(Request $request, string $slug)
183     {
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()),
190             'tags'             => ['array'],
191         ]);
192
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']);
197         }
198
199         $bookIds = explode(',', $request->get('books', ''));
200         $shelf = $this->shelfRepo->update($shelf, $validated, $bookIds);
201
202         return redirect($shelf->getUrl());
203     }
204
205     /**
206      * Shows the page to confirm deletion.
207      */
208     public function showDelete(string $slug)
209     {
210         $shelf = $this->queries->findVisibleBySlugOrFail($slug);
211         $this->checkOwnablePermission(Permission::BookshelfDelete, $shelf);
212
213         $this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $shelf->getShortName()]));
214
215         return view('shelves.delete', ['shelf' => $shelf]);
216     }
217
218     /**
219      * Remove the specified bookshelf from storage.
220      *
221      * @throws Exception
222      */
223     public function destroy(string $slug)
224     {
225         $shelf = $this->queries->findVisibleBySlugOrFail($slug);
226         $this->checkOwnablePermission(Permission::BookshelfDelete, $shelf);
227
228         $this->shelfRepo->destroy($shelf);
229
230         return redirect('/shelves');
231     }
232 }