]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/BookController.php
Revised webhooks list to new format
[bookstack] / app / Http / Controllers / BookController.php
1 <?php
2
3 namespace BookStack\Http\Controllers;
4
5 use BookStack\Actions\ActivityQueries;
6 use BookStack\Actions\ActivityType;
7 use BookStack\Actions\View;
8 use BookStack\Entities\Models\Bookshelf;
9 use BookStack\Entities\Repos\BookRepo;
10 use BookStack\Entities\Tools\BookContents;
11 use BookStack\Entities\Tools\Cloner;
12 use BookStack\Entities\Tools\HierarchyTransformer;
13 use BookStack\Entities\Tools\ShelfContext;
14 use BookStack\Exceptions\ImageUploadException;
15 use BookStack\Exceptions\NotFoundException;
16 use BookStack\Facades\Activity;
17 use BookStack\References\ReferenceFetcher;
18 use Illuminate\Http\Request;
19 use Illuminate\Validation\ValidationException;
20 use Throwable;
21
22 class BookController extends Controller
23 {
24     protected BookRepo $bookRepo;
25     protected ShelfContext $shelfContext;
26     protected ReferenceFetcher $referenceFetcher;
27
28     public function __construct(ShelfContext $entityContextManager, BookRepo $bookRepo, ReferenceFetcher $referenceFetcher)
29     {
30         $this->bookRepo = $bookRepo;
31         $this->shelfContext = $entityContextManager;
32         $this->referenceFetcher = $referenceFetcher;
33     }
34
35     /**
36      * Display a listing of the book.
37      */
38     public function index()
39     {
40         $view = setting()->getForCurrentUser('books_view_type');
41         $sort = setting()->getForCurrentUser('books_sort', 'name');
42         $order = setting()->getForCurrentUser('books_sort_order', 'asc');
43
44         $books = $this->bookRepo->getAllPaginated(18, $sort, $order);
45         $recents = $this->isSignedIn() ? $this->bookRepo->getRecentlyViewed(4) : false;
46         $popular = $this->bookRepo->getPopular(4);
47         $new = $this->bookRepo->getRecentlyCreated(4);
48
49         $this->shelfContext->clearShelfContext();
50
51         $this->setPageTitle(trans('entities.books'));
52
53         return view('books.index', [
54             'books'   => $books,
55             'recents' => $recents,
56             'popular' => $popular,
57             'new'     => $new,
58             'view'    => $view,
59             'sort'    => $sort,
60             'order'   => $order,
61         ]);
62     }
63
64     /**
65      * Show the form for creating a new book.
66      */
67     public function create(string $shelfSlug = null)
68     {
69         $this->checkPermission('book-create-all');
70
71         $bookshelf = null;
72         if ($shelfSlug !== null) {
73             $bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail();
74             $this->checkOwnablePermission('bookshelf-update', $bookshelf);
75         }
76
77         $this->setPageTitle(trans('entities.books_create'));
78
79         return view('books.create', [
80             'bookshelf' => $bookshelf,
81         ]);
82     }
83
84     /**
85      * Store a newly created book in storage.
86      *
87      * @throws ImageUploadException
88      * @throws ValidationException
89      */
90     public function store(Request $request, string $shelfSlug = null)
91     {
92         $this->checkPermission('book-create-all');
93         $validated = $this->validate($request, [
94             'name'        => ['required', 'string', 'max:255'],
95             'description' => ['string', 'max:1000'],
96             'image'       => array_merge(['nullable'], $this->getImageValidationRules()),
97             'tags'        => ['array'],
98         ]);
99
100         $bookshelf = null;
101         if ($shelfSlug !== null) {
102             $bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail();
103             $this->checkOwnablePermission('bookshelf-update', $bookshelf);
104         }
105
106         $book = $this->bookRepo->create($validated);
107
108         if ($bookshelf) {
109             $bookshelf->appendBook($book);
110             Activity::add(ActivityType::BOOKSHELF_UPDATE, $bookshelf);
111         }
112
113         return redirect($book->getUrl());
114     }
115
116     /**
117      * Display the specified book.
118      */
119     public function show(Request $request, ActivityQueries $activities, string $slug)
120     {
121         $book = $this->bookRepo->getBySlug($slug);
122         $bookChildren = (new BookContents($book))->getTree(true);
123         $bookParentShelves = $book->shelves()->scopes('visible')->get();
124
125         View::incrementFor($book);
126         if ($request->has('shelf')) {
127             $this->shelfContext->setShelfContext(intval($request->get('shelf')));
128         }
129
130         $this->setPageTitle($book->getShortName());
131
132         return view('books.show', [
133             'book'              => $book,
134             'current'           => $book,
135             'bookChildren'      => $bookChildren,
136             'bookParentShelves' => $bookParentShelves,
137             'activity'          => $activities->entityActivity($book, 20, 1),
138             'referenceCount'    => $this->referenceFetcher->getPageReferenceCountToEntity($book),
139         ]);
140     }
141
142     /**
143      * Show the form for editing the specified book.
144      */
145     public function edit(string $slug)
146     {
147         $book = $this->bookRepo->getBySlug($slug);
148         $this->checkOwnablePermission('book-update', $book);
149         $this->setPageTitle(trans('entities.books_edit_named', ['bookName' => $book->getShortName()]));
150
151         return view('books.edit', ['book' => $book, 'current' => $book]);
152     }
153
154     /**
155      * Update the specified book in storage.
156      *
157      * @throws ImageUploadException
158      * @throws ValidationException
159      * @throws Throwable
160      */
161     public function update(Request $request, string $slug)
162     {
163         $book = $this->bookRepo->getBySlug($slug);
164         $this->checkOwnablePermission('book-update', $book);
165
166         $validated = $this->validate($request, [
167             'name'        => ['required', 'string', 'max:255'],
168             'description' => ['string', 'max:1000'],
169             'image'       => array_merge(['nullable'], $this->getImageValidationRules()),
170             'tags'        => ['array'],
171         ]);
172
173         if ($request->has('image_reset')) {
174             $validated['image'] = null;
175         } elseif (array_key_exists('image', $validated) && is_null($validated['image'])) {
176             unset($validated['image']);
177         }
178
179         $book = $this->bookRepo->update($book, $validated);
180
181         return redirect($book->getUrl());
182     }
183
184     /**
185      * Shows the page to confirm deletion.
186      */
187     public function showDelete(string $bookSlug)
188     {
189         $book = $this->bookRepo->getBySlug($bookSlug);
190         $this->checkOwnablePermission('book-delete', $book);
191         $this->setPageTitle(trans('entities.books_delete_named', ['bookName' => $book->getShortName()]));
192
193         return view('books.delete', ['book' => $book, 'current' => $book]);
194     }
195
196     /**
197      * Remove the specified book from the system.
198      *
199      * @throws Throwable
200      */
201     public function destroy(string $bookSlug)
202     {
203         $book = $this->bookRepo->getBySlug($bookSlug);
204         $this->checkOwnablePermission('book-delete', $book);
205
206         $this->bookRepo->destroy($book);
207
208         return redirect('/books');
209     }
210
211     /**
212      * Show the view to copy a book.
213      *
214      * @throws NotFoundException
215      */
216     public function showCopy(string $bookSlug)
217     {
218         $book = $this->bookRepo->getBySlug($bookSlug);
219         $this->checkOwnablePermission('book-view', $book);
220
221         session()->flashInput(['name' => $book->name]);
222
223         return view('books.copy', [
224             'book' => $book,
225         ]);
226     }
227
228     /**
229      * Create a copy of a book within the requested target destination.
230      *
231      * @throws NotFoundException
232      */
233     public function copy(Request $request, Cloner $cloner, string $bookSlug)
234     {
235         $book = $this->bookRepo->getBySlug($bookSlug);
236         $this->checkOwnablePermission('book-view', $book);
237         $this->checkPermission('book-create-all');
238
239         $newName = $request->get('name') ?: $book->name;
240         $bookCopy = $cloner->cloneBook($book, $newName);
241         $this->showSuccessNotification(trans('entities.books_copy_success'));
242
243         return redirect($bookCopy->getUrl());
244     }
245
246     /**
247      * Convert the chapter to a book.
248      */
249     public function convertToShelf(HierarchyTransformer $transformer, string $bookSlug)
250     {
251         $book = $this->bookRepo->getBySlug($bookSlug);
252         $this->checkOwnablePermission('book-update', $book);
253         $this->checkOwnablePermission('book-delete', $book);
254         $this->checkPermission('bookshelf-create-all');
255         $this->checkPermission('book-create-all');
256
257         $shelf = $transformer->transformBookToShelf($book);
258
259         return redirect($shelf->getUrl());
260     }
261 }