]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/BookController.php
Merge branch 'master' into issue-181
[bookstack] / app / Http / Controllers / BookController.php
1 <?php namespace BookStack\Http\Controllers;
2
3 use Activity;
4 use BookStack\Book;
5 use BookStack\Repos\EntityRepo;
6 use BookStack\Repos\UserRepo;
7 use BookStack\Services\ExportService;
8 use Illuminate\Http\Request;
9 use Illuminate\Http\Response;
10 use Views;
11
12 class BookController extends Controller
13 {
14
15     protected $entityRepo;
16     protected $userRepo;
17     protected $exportService;
18
19     /**
20      * BookController constructor.
21      * @param EntityRepo $entityRepo
22      * @param UserRepo $userRepo
23      * @param ExportService $exportService
24      */
25     public function __construct(EntityRepo $entityRepo, UserRepo $userRepo, ExportService $exportService)
26     {
27         $this->entityRepo = $entityRepo;
28         $this->userRepo = $userRepo;
29         $this->exportService = $exportService;
30         parent::__construct();
31     }
32
33     /**
34      * Display a listing of the book.
35      * @return Response
36      */
37     public function index()
38     {
39         $books = $this->entityRepo->getAllPaginated('book', 16);
40         $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
41         $popular = $this->entityRepo->getPopular('book', 3, 0);
42         $display = $this->currentUser->display;
43         $this->setPageTitle('Books');
44
45         return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular, 'display' => $display]); //added displaly to access user display
46     }
47
48     /**
49      * Show the form for creating a new book.
50      * @return Response
51      */
52     public function create()
53     {
54         $this->checkPermission('book-create-all');
55         $this->setPageTitle(trans('entities.books_create'));
56         return view('books/create');
57     }
58
59     /**
60      * Store a newly created book in storage.
61      *
62      * @param  Request $request
63      * @return Response
64      */
65     public function store(Request $request)
66     {
67         $this->checkPermission('book-create-all');
68         $this->validate($request, [
69             'name' => 'required|string|max:255',
70             'description' => 'string|max:1000'
71         ]);
72         $image = $request->file('image');
73         $input = time().'-'.$image->getClientOriginalName();
74         $destinationPath = public_path('uploads/book/');
75         $image->move($destinationPath, $input);
76         $path = baseUrl('/uploads/book/').'/'.$input;
77         $book = $this->entityRepo->createFromInput('book', $request->all());
78         $book->image = $path; 
79         $book->save();
80         Activity::add($book, 'book_create', $book->id);
81         return redirect($book->getUrl());
82     }
83
84     /**
85      * Display the specified book.
86      * @param $slug
87      * @return Response
88      */
89     public function show($slug)
90     {
91         $book = $this->entityRepo->getBySlug('book', $slug);
92         $this->checkOwnablePermission('book-view', $book);
93         $bookChildren = $this->entityRepo->getBookChildren($book);
94         Views::add($book);
95         $this->setPageTitle($book->getShortName());
96         return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]);
97     }
98
99     /**
100      * Show the form for editing the specified book.
101      * @param $slug
102      * @return Response
103      */
104     public function edit($slug)
105     {
106         $book = $this->entityRepo->getBySlug('book', $slug);
107         $this->checkOwnablePermission('book-update', $book);
108         $this->setPageTitle(trans('entities.books_edit_named',['bookName'=>$book->getShortName()]));
109         return view('books/edit', ['book' => $book, 'current' => $book]);
110     }
111
112     /**
113      * Update the specified book in storage.
114      * @param  Request $request
115      * @param          $slug
116      * @return Response
117      */
118     public function update(Request $request, $slug)
119     {
120         $book = $this->entityRepo->getBySlug('book', $slug);
121         $this->checkOwnablePermission('book-update', $book);
122         $this->validate($request, [
123             'name' => 'required|string|max:255',
124             'description' => 'string|max:1000'
125         ]);
126             
127             $input = $request->file('image')->getClientOriginalName();
128             echo $input;
129          $destinationPath = public_path('uploads/book/');
130          $request->file('image')->move($destinationPath, $input);
131          $path = baseUrl('/uploads/book/').'/'.$input;
132          $book = $this->entityRepo->updateFromInput('book', $book, $request->all());
133          $book->image = $path; 
134          $book->save();
135          Activity::add($book, 'book_update', $book->id);
136          return redirect($book->getUrl());
137     }
138
139     /**
140      * Shows the page to confirm deletion
141      * @param $bookSlug
142      * @return \Illuminate\View\View
143      */
144     public function showDelete($bookSlug)
145     {
146         $book = $this->entityRepo->getBySlug('book', $bookSlug);
147         $this->checkOwnablePermission('book-delete', $book);
148         $this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()]));
149         return view('books/delete', ['book' => $book, 'current' => $book]);
150     }
151
152     /**
153      * Shows the view which allows pages to be re-ordered and sorted.
154      * @param string $bookSlug
155      * @return \Illuminate\View\View
156      */
157     public function sort($bookSlug)
158     {
159         $book = $this->entityRepo->getBySlug('book', $bookSlug);
160         $this->checkOwnablePermission('book-update', $book);
161         $bookChildren = $this->entityRepo->getBookChildren($book, true);
162         $books = $this->entityRepo->getAll('book', false);
163         $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()]));
164         return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]);
165     }
166
167     /**
168      * Shows the sort box for a single book.
169      * Used via AJAX when loading in extra books to a sort.
170      * @param $bookSlug
171      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
172      */
173     public function getSortItem($bookSlug)
174     {
175         $book = $this->entityRepo->getBySlug('book', $bookSlug);
176         $bookChildren = $this->entityRepo->getBookChildren($book);
177         return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]);
178     }
179
180     /**
181      * Saves an array of sort mapping to pages and chapters.
182      * @param  string $bookSlug
183      * @param Request $request
184      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
185      */
186     public function saveSort($bookSlug, Request $request)
187     {
188         $book = $this->entityRepo->getBySlug('book', $bookSlug);
189         $this->checkOwnablePermission('book-update', $book);
190
191         // Return if no map sent
192         if (!$request->has('sort-tree')) {
193             return redirect($book->getUrl());
194         }
195
196         // Sort pages and chapters
197         $sortedBooks = [];
198         $updatedModels = collect();
199         $sortMap = json_decode($request->get('sort-tree'));
200         $defaultBookId = $book->id;
201
202         // Loop through contents of provided map and update entities accordingly
203         foreach ($sortMap as $bookChild) {
204             $priority = $bookChild->sort;
205             $id = intval($bookChild->id);
206             $isPage = $bookChild->type == 'page';
207             $bookId = $this->entityRepo->exists('book', $bookChild->book) ? intval($bookChild->book) : $defaultBookId;
208             $chapterId = ($isPage && $bookChild->parentChapter === false) ? 0 : intval($bookChild->parentChapter);
209             $model = $this->entityRepo->getById($isPage?'page':'chapter', $id);
210
211             // Update models only if there's a change in parent chain or ordering.
212             if ($model->priority !== $priority || $model->book_id !== $bookId || ($isPage && $model->chapter_id !== $chapterId)) {
213                 $this->entityRepo->changeBook($isPage?'page':'chapter', $bookId, $model);
214                 $model->priority = $priority;
215                 if ($isPage) $model->chapter_id = $chapterId;
216                 $model->save();
217                 $updatedModels->push($model);
218             }
219
220             // Store involved books to be sorted later
221             if (!in_array($bookId, $sortedBooks)) {
222                 $sortedBooks[] = $bookId;
223             }
224         }
225
226         // Add activity for books
227         foreach ($sortedBooks as $bookId) {
228             /** @var Book $updatedBook */
229             $updatedBook = $this->entityRepo->getById('book', $bookId);
230             $this->entityRepo->buildJointPermissionsForBook($updatedBook);
231             Activity::add($updatedBook, 'book_sort', $updatedBook->id);
232         }
233
234         return redirect($book->getUrl());
235     }
236
237     /**
238      * Remove the specified book from storage.
239      * @param $bookSlug
240      * @return Response
241      */
242     public function destroy($bookSlug)
243     {
244         $book = $this->entityRepo->getBySlug('book', $bookSlug);
245         $this->checkOwnablePermission('book-delete', $book);
246         Activity::addMessage('book_delete', 0, $book->name);
247         $this->entityRepo->destroyBook($book);
248         return redirect('/books');
249     }
250
251     /**
252      * Show the Restrictions view.
253      * @param $bookSlug
254      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
255      */
256     public function showRestrict($bookSlug)
257     {
258         $book = $this->entityRepo->getBySlug('book', $bookSlug);
259         $this->checkOwnablePermission('restrictions-manage', $book);
260         $roles = $this->userRepo->getRestrictableRoles();
261         return view('books/restrictions', [
262             'book' => $book,
263             'roles' => $roles
264         ]);
265     }
266
267     /**
268      * Set the restrictions for this book.
269      * @param $bookSlug
270      * @param $bookSlug
271      * @param Request $request
272      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
273      */
274     public function restrict($bookSlug, Request $request)
275     {
276         $book = $this->entityRepo->getBySlug('book', $bookSlug);
277         $this->checkOwnablePermission('restrictions-manage', $book);
278         $this->entityRepo->updateEntityPermissionsFromRequest($request, $book);
279         session()->flash('success', trans('entities.books_permissions_updated'));
280         return redirect($book->getUrl());
281     }
282
283     /**
284      * Export a book as a PDF file.
285      * @param string $bookSlug
286      * @return mixed
287      */
288     public function exportPdf($bookSlug)
289     {
290         $book = $this->entityRepo->getBySlug('book', $bookSlug);
291         $pdfContent = $this->exportService->bookToPdf($book);
292         return response()->make($pdfContent, 200, [
293             'Content-Type'        => 'application/octet-stream',
294             'Content-Disposition' => 'attachment; filename="' . $bookSlug . '.pdf'
295         ]);
296     }
297
298     /**
299      * Export a book as a contained HTML file.
300      * @param string $bookSlug
301      * @return mixed
302      */
303     public function exportHtml($bookSlug)
304     {
305         $book = $this->entityRepo->getBySlug('book', $bookSlug);
306         $htmlContent = $this->exportService->bookToContainedHtml($book);
307         return response()->make($htmlContent, 200, [
308             'Content-Type'        => 'application/octet-stream',
309             'Content-Disposition' => 'attachment; filename="' . $bookSlug . '.html'
310         ]);
311     }
312
313     /**
314      * Export a book as a plain text file.
315      * @param $bookSlug
316      * @return mixed
317      */
318     public function exportPlainText($bookSlug)
319     {
320         $book = $this->entityRepo->getBySlug('book', $bookSlug);
321         $htmlContent = $this->exportService->bookToPlainText($book);
322         return response()->make($htmlContent, 200, [
323             'Content-Type'        => 'application/octet-stream',
324             'Content-Disposition' => 'attachment; filename="' . $bookSlug . '.txt'
325         ]);
326     }
327 }