]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/ChapterController.php
7541ad0dbd9811d76d17b7036fd631de07c1916f
[bookstack] / app / Http / Controllers / ChapterController.php
1 <?php
2
3 namespace BookStack\Http\Controllers;
4
5 use BookStack\Actions\View;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Repos\ChapterRepo;
8 use BookStack\Entities\Tools\BookContents;
9 use BookStack\Entities\Tools\Cloner;
10 use BookStack\Entities\Tools\NextPreviousContentLocator;
11 use BookStack\Entities\Tools\PermissionsUpdater;
12 use BookStack\Exceptions\MoveOperationException;
13 use BookStack\Exceptions\NotFoundException;
14 use Illuminate\Http\Request;
15 use Illuminate\Validation\ValidationException;
16 use Throwable;
17
18 class ChapterController extends Controller
19 {
20     protected $chapterRepo;
21
22     /**
23      * ChapterController constructor.
24      */
25     public function __construct(ChapterRepo $chapterRepo)
26     {
27         $this->chapterRepo = $chapterRepo;
28     }
29
30     /**
31      * Show the form for creating a new chapter.
32      */
33     public function create(string $bookSlug)
34     {
35         $book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
36         $this->checkOwnablePermission('chapter-create', $book);
37
38         $this->setPageTitle(trans('entities.chapters_create'));
39
40         return view('chapters.create', ['book' => $book, 'current' => $book]);
41     }
42
43     /**
44      * Store a newly created chapter in storage.
45      *
46      * @throws ValidationException
47      */
48     public function store(Request $request, string $bookSlug)
49     {
50         $this->validate($request, [
51             'name' => ['required', 'string', 'max:255'],
52         ]);
53
54         $book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
55         $this->checkOwnablePermission('chapter-create', $book);
56
57         $chapter = $this->chapterRepo->create($request->all(), $book);
58
59         return redirect($chapter->getUrl());
60     }
61
62     /**
63      * Display the specified chapter.
64      */
65     public function show(string $bookSlug, string $chapterSlug)
66     {
67         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
68         $this->checkOwnablePermission('chapter-view', $chapter);
69
70         $sidebarTree = (new BookContents($chapter->book))->getTree();
71         $pages = $chapter->getVisiblePages();
72         $nextPreviousLocator = new NextPreviousContentLocator($chapter, $sidebarTree);
73         View::incrementFor($chapter);
74
75         $this->setPageTitle($chapter->getShortName());
76
77         return view('chapters.show', [
78             'book'        => $chapter->book,
79             'chapter'     => $chapter,
80             'current'     => $chapter,
81             'sidebarTree' => $sidebarTree,
82             'pages'       => $pages,
83             'next'        => $nextPreviousLocator->getNext(),
84             'previous'    => $nextPreviousLocator->getPrevious(),
85         ]);
86     }
87
88     /**
89      * Show the form for editing the specified chapter.
90      */
91     public function edit(string $bookSlug, string $chapterSlug)
92     {
93         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
94         $this->checkOwnablePermission('chapter-update', $chapter);
95
96         $this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
97
98         return view('chapters.edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
99     }
100
101     /**
102      * Update the specified chapter in storage.
103      *
104      * @throws NotFoundException
105      */
106     public function update(Request $request, string $bookSlug, string $chapterSlug)
107     {
108         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
109         $this->checkOwnablePermission('chapter-update', $chapter);
110
111         $this->chapterRepo->update($chapter, $request->all());
112
113         return redirect($chapter->getUrl());
114     }
115
116     /**
117      * Shows the page to confirm deletion of this chapter.
118      *
119      * @throws NotFoundException
120      */
121     public function showDelete(string $bookSlug, string $chapterSlug)
122     {
123         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
124         $this->checkOwnablePermission('chapter-delete', $chapter);
125
126         $this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
127
128         return view('chapters.delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]);
129     }
130
131     /**
132      * Remove the specified chapter from storage.
133      *
134      * @throws NotFoundException
135      * @throws Throwable
136      */
137     public function destroy(string $bookSlug, string $chapterSlug)
138     {
139         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
140         $this->checkOwnablePermission('chapter-delete', $chapter);
141
142         $this->chapterRepo->destroy($chapter);
143
144         return redirect($chapter->book->getUrl());
145     }
146
147     /**
148      * Show the page for moving a chapter.
149      *
150      * @throws NotFoundException
151      */
152     public function showMove(string $bookSlug, string $chapterSlug)
153     {
154         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
155         $this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
156         $this->checkOwnablePermission('chapter-update', $chapter);
157         $this->checkOwnablePermission('chapter-delete', $chapter);
158
159         return view('chapters.move', [
160             'chapter' => $chapter,
161             'book'    => $chapter->book,
162         ]);
163     }
164
165     /**
166      * Perform the move action for a chapter.
167      *
168      * @throws NotFoundException
169      */
170     public function move(Request $request, string $bookSlug, string $chapterSlug)
171     {
172         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
173         $this->checkOwnablePermission('chapter-update', $chapter);
174         $this->checkOwnablePermission('chapter-delete', $chapter);
175
176         $entitySelection = $request->get('entity_selection', null);
177         if ($entitySelection === null || $entitySelection === '') {
178             return redirect($chapter->getUrl());
179         }
180
181         try {
182             $newBook = $this->chapterRepo->move($chapter, $entitySelection);
183         } catch (MoveOperationException $exception) {
184             $this->showErrorNotification(trans('errors.selected_book_not_found'));
185
186             return redirect()->back();
187         }
188
189         $this->showSuccessNotification(trans('entities.chapter_move_success', ['bookName' => $newBook->name]));
190
191         return redirect($chapter->getUrl());
192     }
193
194     /**
195      * Show the view to copy a chapter.
196      *
197      * @throws NotFoundException
198      */
199     public function showCopy(string $bookSlug, string $chapterSlug)
200     {
201         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
202         $this->checkOwnablePermission('chapter-view', $chapter);
203
204         session()->flashInput(['name' => $chapter->name]);
205
206         return view('chapters.copy', [
207             'book'    => $chapter->book,
208             'chapter' => $chapter,
209         ]);
210     }
211
212     /**
213      * Create a copy of a chapter within the requested target destination.
214      *
215      * @throws NotFoundException
216      * @throws Throwable
217      */
218     public function copy(Request $request, Cloner $cloner, string $bookSlug, string $chapterSlug)
219     {
220         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
221         $this->checkOwnablePermission('chapter-view', $chapter);
222
223         $entitySelection = $request->get('entity_selection') ?: null;
224         $newParentBook = $entitySelection ? $this->chapterRepo->findParentByIdentifier($entitySelection) : $chapter->getParent();
225
226         if (is_null($newParentBook)) {
227             $this->showErrorNotification(trans('errors.selected_book_not_found'));
228
229             return redirect()->back();
230         }
231
232         $this->checkOwnablePermission('chapter-create', $newParentBook);
233
234         $newName = $request->get('name') ?: $chapter->name;
235         $chapterCopy = $cloner->cloneChapter($chapter, $newParentBook, $newName);
236         $this->showSuccessNotification(trans('entities.chapters_copy_success'));
237
238         return redirect($chapterCopy->getUrl());
239     }
240
241     /**
242      * Show the Restrictions view.
243      *
244      * @throws NotFoundException
245      */
246     public function showPermissions(string $bookSlug, string $chapterSlug)
247     {
248         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
249         $this->checkOwnablePermission('restrictions-manage', $chapter);
250
251         return view('chapters.permissions', [
252             'chapter' => $chapter,
253         ]);
254     }
255
256     /**
257      * Set the restrictions for this chapter.
258      *
259      * @throws NotFoundException
260      */
261     public function permissions(Request $request, PermissionsUpdater $permissionsUpdater, string $bookSlug, string $chapterSlug)
262     {
263         $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
264         $this->checkOwnablePermission('restrictions-manage', $chapter);
265
266         $permissionsUpdater->updateFromPermissionsForm($chapter, $request);
267
268         $this->showSuccessNotification(trans('entities.chapters_permissions_success'));
269
270         return redirect($chapter->getUrl());
271     }
272 }