]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/PageController.php
Added restriction tests and fixed any bugs in the process
[bookstack] / app / Http / Controllers / PageController.php
1 <?php namespace BookStack\Http\Controllers;
2
3 use Activity;
4 use BookStack\Exceptions\NotFoundException;
5 use BookStack\Repos\UserRepo;
6 use BookStack\Services\ExportService;
7 use Illuminate\Http\Request;
8 use BookStack\Http\Requests;
9 use BookStack\Repos\BookRepo;
10 use BookStack\Repos\ChapterRepo;
11 use BookStack\Repos\PageRepo;
12 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
13 use Views;
14
15 class PageController extends Controller
16 {
17
18     protected $pageRepo;
19     protected $bookRepo;
20     protected $chapterRepo;
21     protected $exportService;
22     protected $userRepo;
23
24     /**
25      * PageController constructor.
26      * @param PageRepo $pageRepo
27      * @param BookRepo $bookRepo
28      * @param ChapterRepo $chapterRepo
29      * @param ExportService $exportService
30      * @param UserRepo $userRepo
31      */
32     public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ExportService $exportService, UserRepo $userRepo)
33     {
34         $this->pageRepo = $pageRepo;
35         $this->bookRepo = $bookRepo;
36         $this->chapterRepo = $chapterRepo;
37         $this->exportService = $exportService;
38         $this->userRepo = $userRepo;
39         parent::__construct();
40     }
41
42     /**
43      * Show the form for creating a new page.
44      * @param      $bookSlug
45      * @param bool $chapterSlug
46      * @return Response
47      * @internal param bool $pageSlug
48      */
49     public function create($bookSlug, $chapterSlug = false)
50     {
51         $book = $this->bookRepo->getBySlug($bookSlug);
52         $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false;
53         $parent = $chapter ? $chapter : $book;
54         $this->checkOwnablePermission('page-create', $parent);
55         $this->setPageTitle('Create New Page');
56         return view('pages/create', ['book' => $book, 'chapter' => $chapter]);
57     }
58
59     /**
60      * Store a newly created page in storage.
61      * @param  Request $request
62      * @param          $bookSlug
63      * @return Response
64      */
65     public function store(Request $request, $bookSlug)
66     {
67         $this->validate($request, [
68             'name'   => 'required|string|max:255'
69         ]);
70
71         $input = $request->all();
72         $book = $this->bookRepo->getBySlug($bookSlug);
73         $chapterId = ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) ? $request->get('chapter') : null;
74         $parent = $chapterId !== null ? $this->chapterRepo->getById($chapterId) : $book;
75         $this->checkOwnablePermission('page-create', $parent);
76         $input['priority'] = $this->bookRepo->getNewPriority($book);
77
78         $page = $this->pageRepo->saveNew($input, $book, $chapterId);
79
80         Activity::add($page, 'page_create', $book->id);
81         return redirect($page->getUrl());
82     }
83
84     /**
85      * Display the specified page.
86      * If the page is not found via the slug the
87      * revisions are searched for a match.
88      * @param $bookSlug
89      * @param $pageSlug
90      * @return Response
91      */
92     public function show($bookSlug, $pageSlug)
93     {
94         $book = $this->bookRepo->getBySlug($bookSlug);
95
96         try {
97             $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
98         } catch (NotFoundException $e) {
99             $page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
100             if ($page === null) abort(404);
101             return redirect($page->getUrl());
102         }
103
104         $sidebarTree = $this->bookRepo->getChildren($book);
105         Views::add($page);
106         $this->setPageTitle($page->getShortName());
107         return view('pages/show', ['page' => $page, 'book' => $book, 'current' => $page, 'sidebarTree' => $sidebarTree]);
108     }
109
110     /**
111      * Show the form for editing the specified page.
112      * @param $bookSlug
113      * @param $pageSlug
114      * @return Response
115      */
116     public function edit($bookSlug, $pageSlug)
117     {
118         $book = $this->bookRepo->getBySlug($bookSlug);
119         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
120         $this->checkOwnablePermission('page-update', $page);
121         $this->setPageTitle('Editing Page ' . $page->getShortName());
122         return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]);
123     }
124
125     /**
126      * Update the specified page in storage.
127      * @param  Request $request
128      * @param          $bookSlug
129      * @param          $pageSlug
130      * @return Response
131      */
132     public function update(Request $request, $bookSlug, $pageSlug)
133     {
134         $this->validate($request, [
135             'name'   => 'required|string|max:255'
136         ]);
137         $book = $this->bookRepo->getBySlug($bookSlug);
138         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
139         $this->checkOwnablePermission('page-update', $page);
140         $this->pageRepo->updatePage($page, $book->id, $request->all());
141         Activity::add($page, 'page_update', $book->id);
142         return redirect($page->getUrl());
143     }
144
145     /**
146      * Redirect from a special link url which
147      * uses the page id rather than the name.
148      * @param $pageId
149      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
150      */
151     public function redirectFromLink($pageId)
152     {
153         $page = $this->pageRepo->getById($pageId);
154         return redirect($page->getUrl());
155     }
156
157     /**
158      * Show the deletion page for the specified page.
159      * @param $bookSlug
160      * @param $pageSlug
161      * @return \Illuminate\View\View
162      */
163     public function showDelete($bookSlug, $pageSlug)
164     {
165         $book = $this->bookRepo->getBySlug($bookSlug);
166         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
167         $this->checkOwnablePermission('page-delete', $page);
168         $this->setPageTitle('Delete Page ' . $page->getShortName());
169         return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
170     }
171
172     /**
173      * Remove the specified page from storage.
174      *
175      * @param $bookSlug
176      * @param $pageSlug
177      * @return Response
178      * @internal param int $id
179      */
180     public function destroy($bookSlug, $pageSlug)
181     {
182         $book = $this->bookRepo->getBySlug($bookSlug);
183         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
184         $this->checkOwnablePermission('page-delete', $page);
185         Activity::addMessage('page_delete', $book->id, $page->name);
186         $this->pageRepo->destroy($page);
187         return redirect($book->getUrl());
188     }
189
190     /**
191      * Shows the last revisions for this page.
192      * @param $bookSlug
193      * @param $pageSlug
194      * @return \Illuminate\View\View
195      */
196     public function showRevisions($bookSlug, $pageSlug)
197     {
198         $book = $this->bookRepo->getBySlug($bookSlug);
199         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
200         $this->setPageTitle('Revisions For ' . $page->getShortName());
201         return view('pages/revisions', ['page' => $page, 'book' => $book, 'current' => $page]);
202     }
203
204     /**
205      * Shows a preview of a single revision
206      * @param $bookSlug
207      * @param $pageSlug
208      * @param $revisionId
209      * @return \Illuminate\View\View
210      */
211     public function showRevision($bookSlug, $pageSlug, $revisionId)
212     {
213         $book = $this->bookRepo->getBySlug($bookSlug);
214         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
215         $revision = $this->pageRepo->getRevisionById($revisionId);
216         $page->fill($revision->toArray());
217         $this->setPageTitle('Page Revision For ' . $page->getShortName());
218         return view('pages/revision', ['page' => $page, 'book' => $book]);
219     }
220
221     /**
222      * Restores a page using the content of the specified revision.
223      * @param $bookSlug
224      * @param $pageSlug
225      * @param $revisionId
226      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
227      */
228     public function restoreRevision($bookSlug, $pageSlug, $revisionId)
229     {
230         $book = $this->bookRepo->getBySlug($bookSlug);
231         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
232         $this->checkOwnablePermission('page-update', $page);
233         $page = $this->pageRepo->restoreRevision($page, $book, $revisionId);
234         Activity::add($page, 'page_restore', $book->id);
235         return redirect($page->getUrl());
236     }
237
238     /**
239      * Exports a page to pdf format using barryvdh/laravel-dompdf wrapper.
240      * https://github.com/barryvdh/laravel-dompdf
241      * @param $bookSlug
242      * @param $pageSlug
243      * @return \Illuminate\Http\Response
244      */
245     public function exportPdf($bookSlug, $pageSlug)
246     {
247         $book = $this->bookRepo->getBySlug($bookSlug);
248         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
249         $pdfContent = $this->exportService->pageToPdf($page);
250         return response()->make($pdfContent, 200, [
251             'Content-Type' => 'application/octet-stream',
252             'Content-Disposition' => 'attachment; filename="'.$pageSlug.'.pdf'
253         ]);
254     }
255
256     /**
257      * Export a page to a self-contained HTML file.
258      * @param $bookSlug
259      * @param $pageSlug
260      * @return \Illuminate\Http\Response
261      */
262     public function exportHtml($bookSlug, $pageSlug)
263     {
264         $book = $this->bookRepo->getBySlug($bookSlug);
265         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
266         $containedHtml = $this->exportService->pageToContainedHtml($page);
267         return response()->make($containedHtml, 200, [
268             'Content-Type' => 'application/octet-stream',
269             'Content-Disposition' => 'attachment; filename="'.$pageSlug.'.html'
270         ]);
271     }
272
273     /**
274      * Export a page to a simple plaintext .txt file.
275      * @param $bookSlug
276      * @param $pageSlug
277      * @return \Illuminate\Http\Response
278      */
279     public function exportPlainText($bookSlug, $pageSlug)
280     {
281         $book = $this->bookRepo->getBySlug($bookSlug);
282         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
283         $containedHtml = $this->exportService->pageToPlainText($page);
284         return response()->make($containedHtml, 200, [
285             'Content-Type' => 'application/octet-stream',
286             'Content-Disposition' => 'attachment; filename="'.$pageSlug.'.txt'
287         ]);
288     }
289
290     /**
291      * Show a listing of recently created pages
292      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
293      */
294     public function showRecentlyCreated()
295     {
296         $pages = $this->pageRepo->getRecentlyCreatedPaginated(20);
297         return view('pages/detailed-listing', [
298             'title' => 'Recently Created Pages',
299             'pages' => $pages
300         ]);
301     }
302
303     /**
304      * Show a listing of recently created pages
305      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
306      */
307     public function showRecentlyUpdated()
308     {
309         $pages = $this->pageRepo->getRecentlyUpdatedPaginated(20);
310         return view('pages/detailed-listing', [
311             'title' => 'Recently Updated Pages',
312             'pages' => $pages
313         ]);
314     }
315
316     /**
317      * Show the Restrictions view.
318      * @param $bookSlug
319      * @param $pageSlug
320      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
321      */
322     public function showRestrict($bookSlug, $pageSlug)
323     {
324         $book = $this->bookRepo->getBySlug($bookSlug);
325         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
326         $this->checkOwnablePermission('restrictions-manage', $page);
327         $roles = $this->userRepo->getRestrictableRoles();
328         return view('pages/restrictions', [
329             'page' => $page,
330             'roles' => $roles
331         ]);
332     }
333
334     /**
335      * Set the restrictions for this page.
336      * @param $bookSlug
337      * @param $pageSlug
338      * @param Request $request
339      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
340      */
341     public function restrict($bookSlug, $pageSlug, Request $request)
342     {
343         $book = $this->bookRepo->getBySlug($bookSlug);
344         $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
345         $this->checkOwnablePermission('restrictions-manage', $page);
346         $this->pageRepo->updateRestrictionsFromRequest($request, $page);
347         session()->flash('success', 'Page Restrictions Updated');
348         return redirect($page->getUrl());
349     }
350
351 }