]> BookStack Code Mirror - bookstack/blob - app/Entities/Controllers/ChapterApiController.php
Queries: Updated all app book static query uses
[bookstack] / app / Entities / Controllers / ChapterApiController.php
1 <?php
2
3 namespace BookStack\Entities\Controllers;
4
5 use BookStack\Entities\Models\Chapter;
6 use BookStack\Entities\Queries\BookQueries;
7 use BookStack\Entities\Queries\ChapterQueries;
8 use BookStack\Entities\Repos\ChapterRepo;
9 use BookStack\Exceptions\PermissionsException;
10 use BookStack\Http\ApiController;
11 use Exception;
12 use Illuminate\Database\Eloquent\Relations\HasMany;
13 use Illuminate\Http\Request;
14
15 class ChapterApiController extends ApiController
16 {
17     protected $rules = [
18         'create' => [
19             'book_id'             => ['required', 'integer'],
20             'name'                => ['required', 'string', 'max:255'],
21             'description'         => ['string', 'max:1900'],
22             'description_html'    => ['string', 'max:2000'],
23             'tags'                => ['array'],
24             'priority'            => ['integer'],
25             'default_template_id' => ['nullable', 'integer'],
26         ],
27         'update' => [
28             'book_id'             => ['integer'],
29             'name'                => ['string', 'min:1', 'max:255'],
30             'description'         => ['string', 'max:1900'],
31             'description_html'    => ['string', 'max:2000'],
32             'tags'                => ['array'],
33             'priority'            => ['integer'],
34             'default_template_id' => ['nullable', 'integer'],
35         ],
36     ];
37
38     public function __construct(
39         protected ChapterRepo $chapterRepo,
40         protected ChapterQueries $queries,
41         protected BookQueries $bookQueries,
42     ) {
43     }
44
45     /**
46      * Get a listing of chapters visible to the user.
47      */
48     public function list()
49     {
50         $chapters = $this->queries->visibleForList();
51
52         return $this->apiListingResponse($chapters, [
53             'id', 'book_id', 'name', 'slug', 'description', 'priority',
54             'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
55         ]);
56     }
57
58     /**
59      * Create a new chapter in the system.
60      */
61     public function create(Request $request)
62     {
63         $requestData = $this->validate($request, $this->rules['create']);
64
65         $bookId = $request->get('book_id');
66         $book = $this->bookQueries->findVisibleByIdOrFail(intval($bookId));
67         $this->checkOwnablePermission('chapter-create', $book);
68
69         $chapter = $this->chapterRepo->create($requestData, $book);
70
71         return response()->json($this->forJsonDisplay($chapter));
72     }
73
74     /**
75      * View the details of a single chapter.
76      */
77     public function read(string $id)
78     {
79         $chapter = $this->queries->findVisibleByIdOrFail(intval($id));
80         $chapter = $this->forJsonDisplay($chapter);
81
82         $chapter->load([
83             'createdBy', 'updatedBy', 'ownedBy',
84             'pages' => function (HasMany $query) {
85                 $query->scopes('visible')->get(['id', 'name', 'slug']);
86             }
87         ]);
88
89         return response()->json($chapter);
90     }
91
92     /**
93      * Update the details of a single chapter.
94      * Providing a 'book_id' property will essentially move the chapter
95      * into that parent element if you have permissions to do so.
96      */
97     public function update(Request $request, string $id)
98     {
99         $requestData = $this->validate($request, $this->rules()['update']);
100         $chapter = $this->queries->findVisibleByIdOrFail(intval($id));
101         $this->checkOwnablePermission('chapter-update', $chapter);
102
103         if ($request->has('book_id') && $chapter->book_id !== intval($requestData['book_id'])) {
104             $this->checkOwnablePermission('chapter-delete', $chapter);
105
106             try {
107                 $this->chapterRepo->move($chapter, "book:{$requestData['book_id']}");
108             } catch (Exception $exception) {
109                 if ($exception instanceof PermissionsException) {
110                     $this->showPermissionError();
111                 }
112
113                 return $this->jsonError(trans('errors.selected_book_not_found'));
114             }
115         }
116
117         $updatedChapter = $this->chapterRepo->update($chapter, $requestData);
118
119         return response()->json($this->forJsonDisplay($updatedChapter));
120     }
121
122     /**
123      * Delete a chapter.
124      * This will typically send the chapter to the recycle bin.
125      */
126     public function delete(string $id)
127     {
128         $chapter = $this->queries->findVisibleByIdOrFail(intval($id));
129         $this->checkOwnablePermission('chapter-delete', $chapter);
130
131         $this->chapterRepo->destroy($chapter);
132
133         return response('', 204);
134     }
135
136     protected function forJsonDisplay(Chapter $chapter): Chapter
137     {
138         $chapter = clone $chapter;
139         $chapter->unsetRelations()->refresh();
140
141         $chapter->load(['tags']);
142         $chapter->makeVisible('description_html');
143         $chapter->setAttribute('description_html', $chapter->descriptionHtml());
144         $chapter->setAttribute('book_slug', $chapter->book()->first()->slug);
145
146         return $chapter;
147     }
148 }