mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-10-26 11:11:56 +00:00
Some checks are pending
analyse-php / build (push) Waiting to run
lint-php / build (push) Waiting to run
test-migrations / build (8.2) (push) Waiting to run
test-migrations / build (8.3) (push) Waiting to run
test-migrations / build (8.4) (push) Waiting to run
test-php / build (8.2) (push) Waiting to run
test-php / build (8.3) (push) Waiting to run
test-php / build (8.4) (push) Waiting to run
Updated base entity class, and worked through BaseRepo. Need to go through other repos next. Removed a couple of redundant interfaces as part of this since we can move the logic onto the shared ContainerData model as needed.
155 lines
5.4 KiB
PHP
155 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace BookStack\Entities\Controllers;
|
|
|
|
use BookStack\Api\ApiEntityListFormatter;
|
|
use BookStack\Entities\Models\Book;
|
|
use BookStack\Entities\Models\Chapter;
|
|
use BookStack\Entities\Models\Entity;
|
|
use BookStack\Entities\Queries\BookQueries;
|
|
use BookStack\Entities\Queries\PageQueries;
|
|
use BookStack\Entities\Repos\BookRepo;
|
|
use BookStack\Entities\Tools\BookContents;
|
|
use BookStack\Http\ApiController;
|
|
use BookStack\Permissions\Permission;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class BookApiController extends ApiController
|
|
{
|
|
public function __construct(
|
|
protected BookRepo $bookRepo,
|
|
protected BookQueries $queries,
|
|
protected PageQueries $pageQueries,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Get a listing of books visible to the user.
|
|
*/
|
|
public function list()
|
|
{
|
|
$books = $this->queries
|
|
->visibleForList()
|
|
->with(['cover:id,name,url'])
|
|
->addSelect(['created_by', 'updated_by']);
|
|
|
|
return $this->apiListingResponse($books, [
|
|
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Create a new book in the system.
|
|
* The cover image of a book can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
|
|
* If the 'image' property is null then the book cover image will be removed.
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function create(Request $request)
|
|
{
|
|
$this->checkPermission(Permission::BookCreateAll);
|
|
$requestData = $this->validate($request, $this->rules()['create']);
|
|
|
|
$book = $this->bookRepo->create($requestData);
|
|
|
|
return response()->json($this->forJsonDisplay($book));
|
|
}
|
|
|
|
/**
|
|
* View the details of a single book.
|
|
* The response data will contain 'content' property listing the chapter and pages directly within, in
|
|
* the same structure as you'd see within the BookStack interface when viewing a book. Top-level
|
|
* contents will have a 'type' property to distinguish between pages & chapters.
|
|
*/
|
|
public function read(string $id)
|
|
{
|
|
$book = $this->queries->findVisibleByIdOrFail(intval($id));
|
|
$book = $this->forJsonDisplay($book);
|
|
$book->load(['createdBy', 'updatedBy', 'ownedBy']);
|
|
|
|
$contents = (new BookContents($book))->getTree(true, false)->all();
|
|
$contentsApiData = (new ApiEntityListFormatter($contents))
|
|
->withType()
|
|
->withField('pages', function (Entity $entity) {
|
|
if ($entity instanceof Chapter) {
|
|
$pages = $this->pageQueries->visibleForChapterList($entity->id)->get()->all();
|
|
return (new ApiEntityListFormatter($pages))->format();
|
|
}
|
|
return null;
|
|
})->format();
|
|
$book->setAttribute('contents', $contentsApiData);
|
|
|
|
return response()->json($book);
|
|
}
|
|
|
|
/**
|
|
* Update the details of a single book.
|
|
* The cover image of a book can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
|
|
* If the 'image' property is null then the book cover image will be removed.
|
|
*
|
|
* @throws ValidationException
|
|
*/
|
|
public function update(Request $request, string $id)
|
|
{
|
|
$book = $this->queries->findVisibleByIdOrFail(intval($id));
|
|
$this->checkOwnablePermission(Permission::BookUpdate, $book);
|
|
|
|
$requestData = $this->validate($request, $this->rules()['update']);
|
|
$book = $this->bookRepo->update($book, $requestData);
|
|
|
|
return response()->json($this->forJsonDisplay($book));
|
|
}
|
|
|
|
/**
|
|
* Delete a single book.
|
|
* This will typically send the book to the recycle bin.
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public function delete(string $id)
|
|
{
|
|
$book = $this->queries->findVisibleByIdOrFail(intval($id));
|
|
$this->checkOwnablePermission(Permission::BookDelete, $book);
|
|
|
|
$this->bookRepo->destroy($book);
|
|
|
|
return response('', 204);
|
|
}
|
|
|
|
protected function forJsonDisplay(Book $book): Book
|
|
{
|
|
$book = clone $book;
|
|
$book->unsetRelations()->refresh();
|
|
|
|
$book->load(['tags']);
|
|
$book->makeVisible(['cover', 'description_html'])
|
|
->setAttribute('description_html', $book->containerData->getDescriptionHtml())
|
|
->setAttribute('cover', $book->containerData->cover);
|
|
|
|
return $book;
|
|
}
|
|
|
|
protected function rules(): array
|
|
{
|
|
return [
|
|
'create' => [
|
|
'name' => ['required', 'string', 'max:255'],
|
|
'description' => ['string', 'max:1900'],
|
|
'description_html' => ['string', 'max:2000'],
|
|
'tags' => ['array'],
|
|
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
|
|
'default_template_id' => ['nullable', 'integer'],
|
|
],
|
|
'update' => [
|
|
'name' => ['string', 'min:1', 'max:255'],
|
|
'description' => ['string', 'max:1900'],
|
|
'description_html' => ['string', 'max:2000'],
|
|
'tags' => ['array'],
|
|
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
|
|
'default_template_id' => ['nullable', 'integer'],
|
|
],
|
|
];
|
|
}
|
|
}
|