From 00ae04e0bd7f9d80aa80334b8a8bb55e7ca33cad Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 21 Dec 2023 13:23:52 +0000 Subject: [PATCH] Input WYSIWYG: Updated API to show/accept html descriptions Also aligned books, shelves and chapters to return description content and some relations (where not breaking API) in create/update responses also so that information can be seen direct from that input in a request. API docs and tests not yet updated to match. --- .../Controllers/BookApiController.php | 40 +++++++++----- .../Controllers/BookshelfApiController.php | 54 ++++++++++++------- .../Controllers/ChapterApiController.php | 52 ++++++++++++------ app/Entities/Models/Book.php | 2 +- app/Entities/Models/Bookshelf.php | 2 +- app/Entities/Models/Chapter.php | 2 +- dev/api/responses/books-read.json | 1 + dev/api/responses/chapters-read.json | 1 + dev/api/responses/shelves-read.json | 1 + 9 files changed, 103 insertions(+), 52 deletions(-) diff --git a/app/Entities/Controllers/BookApiController.php b/app/Entities/Controllers/BookApiController.php index 41ff11dde..aa21aea47 100644 --- a/app/Entities/Controllers/BookApiController.php +++ b/app/Entities/Controllers/BookApiController.php @@ -45,7 +45,7 @@ class BookApiController extends ApiController $book = $this->bookRepo->create($requestData); - return response()->json($book); + return response()->json($this->forJsonDisplay($book)); } /** @@ -56,9 +56,9 @@ class BookApiController extends ApiController */ public function read(string $id) { - $book = Book::visible() - ->with(['tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy']) - ->findOrFail($id); + $book = Book::visible()->findOrFail($id); + $book = $this->forJsonDisplay($book); + $book->load(['createdBy', 'updatedBy', 'ownedBy']); $contents = (new BookContents($book))->getTree(true, false)->all(); $contentsApiData = (new ApiEntityListFormatter($contents)) @@ -89,7 +89,7 @@ class BookApiController extends ApiController $requestData = $this->validate($request, $this->rules()['update']); $book = $this->bookRepo->update($book, $requestData); - return response()->json($book); + return response()->json($this->forJsonDisplay($book)); } /** @@ -108,21 +108,35 @@ class BookApiController extends ApiController return response('', 204); } + protected function forJsonDisplay(Book $book): Book + { + $book = clone $book; + $book->unsetRelations()->refresh(); + + $book->load(['tags', 'cover']); + $book->makeVisible('description_html') + ->setAttribute('description_html', $book->descriptionHtml()); + + return $book; + } + protected function rules(): array { return [ 'create' => [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + '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:1000'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + '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'], ], ]; diff --git a/app/Entities/Controllers/BookshelfApiController.php b/app/Entities/Controllers/BookshelfApiController.php index 9bdb8256d..a12dc90ac 100644 --- a/app/Entities/Controllers/BookshelfApiController.php +++ b/app/Entities/Controllers/BookshelfApiController.php @@ -12,11 +12,9 @@ use Illuminate\Validation\ValidationException; class BookshelfApiController extends ApiController { - protected BookshelfRepo $bookshelfRepo; - - public function __construct(BookshelfRepo $bookshelfRepo) - { - $this->bookshelfRepo = $bookshelfRepo; + public function __construct( + protected BookshelfRepo $bookshelfRepo + ) { } /** @@ -48,7 +46,7 @@ class BookshelfApiController extends ApiController $bookIds = $request->get('books', []); $shelf = $this->bookshelfRepo->create($requestData, $bookIds); - return response()->json($shelf); + return response()->json($this->forJsonDisplay($shelf)); } /** @@ -56,12 +54,14 @@ class BookshelfApiController extends ApiController */ public function read(string $id) { - $shelf = Bookshelf::visible()->with([ - 'tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy', + $shelf = Bookshelf::visible()->findOrFail($id); + $shelf = $this->forJsonDisplay($shelf); + $shelf->load([ + 'createdBy', 'updatedBy', 'ownedBy', 'books' => function (BelongsToMany $query) { $query->scopes('visible')->get(['id', 'name', 'slug']); }, - ])->findOrFail($id); + ]); return response()->json($shelf); } @@ -86,7 +86,7 @@ class BookshelfApiController extends ApiController $shelf = $this->bookshelfRepo->update($shelf, $requestData, $bookIds); - return response()->json($shelf); + return response()->json($this->forJsonDisplay($shelf)); } /** @@ -105,22 +105,36 @@ class BookshelfApiController extends ApiController return response('', 204); } + protected function forJsonDisplay(Bookshelf $shelf): Bookshelf + { + $shelf = clone $shelf; + $shelf->unsetRelations()->refresh(); + + $shelf->load(['tags', 'cover']); + $shelf->makeVisible('description_html') + ->setAttribute('description_html', $shelf->descriptionHtml()); + + return $shelf; + } + protected function rules(): array { return [ 'create' => [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'books' => ['array'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'name' => ['required', 'string', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'books' => ['array'], + 'tags' => ['array'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), ], 'update' => [ - 'name' => ['string', 'min:1', 'max:255'], - 'description' => ['string', 'max:1000'], - 'books' => ['array'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'name' => ['string', 'min:1', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'books' => ['array'], + 'tags' => ['array'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), ], ]; } diff --git a/app/Entities/Controllers/ChapterApiController.php b/app/Entities/Controllers/ChapterApiController.php index 7f01e445a..c21323262 100644 --- a/app/Entities/Controllers/ChapterApiController.php +++ b/app/Entities/Controllers/ChapterApiController.php @@ -15,18 +15,20 @@ class ChapterApiController extends ApiController { protected $rules = [ 'create' => [ - 'book_id' => ['required', 'integer'], - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'priority' => ['integer'], + 'book_id' => ['required', 'integer'], + 'name' => ['required', 'string', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'priority' => ['integer'], ], 'update' => [ - 'book_id' => ['integer'], - 'name' => ['string', 'min:1', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'priority' => ['integer'], + 'book_id' => ['integer'], + 'name' => ['string', 'min:1', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'priority' => ['integer'], ], ]; @@ -61,7 +63,7 @@ class ChapterApiController extends ApiController $chapter = $this->chapterRepo->create($requestData, $book); - return response()->json($chapter->load(['tags'])); + return response()->json($this->forJsonDisplay($chapter)); } /** @@ -69,9 +71,15 @@ class ChapterApiController extends ApiController */ public function read(string $id) { - $chapter = Chapter::visible()->with(['tags', 'createdBy', 'updatedBy', 'ownedBy', 'pages' => function (HasMany $query) { - $query->scopes('visible')->get(['id', 'name', 'slug']); - }])->findOrFail($id); + $chapter = Chapter::visible()->findOrFail($id); + $chapter = $this->forJsonDisplay($chapter); + + $chapter->load([ + 'createdBy', 'updatedBy', 'ownedBy', + 'pages' => function (HasMany $query) { + $query->scopes('visible')->get(['id', 'name', 'slug']); + } + ]); return response()->json($chapter); } @@ -93,7 +101,7 @@ class ChapterApiController extends ApiController try { $this->chapterRepo->move($chapter, "book:{$requestData['book_id']}"); } catch (Exception $exception) { - if ($exception instanceof PermissionsException) { + if ($exception instanceof PermissionsException) { $this->showPermissionError(); } @@ -103,7 +111,7 @@ class ChapterApiController extends ApiController $updatedChapter = $this->chapterRepo->update($chapter, $requestData); - return response()->json($updatedChapter->load(['tags'])); + return response()->json($this->forJsonDisplay($updatedChapter)); } /** @@ -119,4 +127,16 @@ class ChapterApiController extends ApiController return response('', 204); } + + protected function forJsonDisplay(Chapter $chapter): Chapter + { + $chapter = clone $chapter; + $chapter->unsetRelations()->refresh(); + + $chapter->load(['tags']); + $chapter->makeVisible('description_html') + ->setAttribute('description_html', $chapter->descriptionHtml()); + + return $chapter; + } } diff --git a/app/Entities/Models/Book.php b/app/Entities/Models/Book.php index 52674d839..14cb790c5 100644 --- a/app/Entities/Models/Book.php +++ b/app/Entities/Models/Book.php @@ -31,7 +31,7 @@ class Book extends Entity implements HasCoverImage public float $searchFactor = 1.2; protected $fillable = ['name']; - protected $hidden = ['pivot', 'image_id', 'deleted_at']; + protected $hidden = ['pivot', 'image_id', 'deleted_at', 'description_html']; /** * Get the url for this book. diff --git a/app/Entities/Models/Bookshelf.php b/app/Entities/Models/Bookshelf.php index 464c127b8..9ffa0ea9c 100644 --- a/app/Entities/Models/Bookshelf.php +++ b/app/Entities/Models/Bookshelf.php @@ -19,7 +19,7 @@ class Bookshelf extends Entity implements HasCoverImage protected $fillable = ['name', 'description', 'image_id']; - protected $hidden = ['image_id', 'deleted_at']; + protected $hidden = ['image_id', 'deleted_at', 'description_html']; /** * Get the books in this shelf. diff --git a/app/Entities/Models/Chapter.php b/app/Entities/Models/Chapter.php index 6c5f059ac..f30d77b5c 100644 --- a/app/Entities/Models/Chapter.php +++ b/app/Entities/Models/Chapter.php @@ -20,7 +20,7 @@ class Chapter extends BookChild public float $searchFactor = 1.2; protected $fillable = ['name', 'description', 'priority']; - protected $hidden = ['pivot', 'deleted_at']; + protected $hidden = ['pivot', 'deleted_at', 'description_html']; /** * Get the pages that this chapter contains. diff --git a/dev/api/responses/books-read.json b/dev/api/responses/books-read.json index 21e1829b8..afeebade6 100644 --- a/dev/api/responses/books-read.json +++ b/dev/api/responses/books-read.json @@ -3,6 +3,7 @@ "name": "My own book", "slug": "my-own-book", "description": "This is my own little book", + "description_html": "

This is my own little book

", "created_at": "2020-01-12T14:09:59.000000Z", "updated_at": "2020-01-12T14:11:51.000000Z", "created_by": { diff --git a/dev/api/responses/chapters-read.json b/dev/api/responses/chapters-read.json index 5f4de85f1..192ffce7c 100644 --- a/dev/api/responses/chapters-read.json +++ b/dev/api/responses/chapters-read.json @@ -4,6 +4,7 @@ "slug": "content-creation", "name": "Content Creation", "description": "How to create documentation on whatever subject you need to write about.", + "description_html": "

How to create documentation on whatever subject you need to write about.

", "priority": 3, "created_at": "2019-05-05T21:49:56.000000Z", "updated_at": "2019-09-28T11:24:23.000000Z", diff --git a/dev/api/responses/shelves-read.json b/dev/api/responses/shelves-read.json index 802045bd8..eca06a46b 100644 --- a/dev/api/responses/shelves-read.json +++ b/dev/api/responses/shelves-read.json @@ -3,6 +3,7 @@ "name": "My shelf", "slug": "my-shelf", "description": "This is my shelf with some books", + "description_html": "

This is my shelf with some books

", "created_by": { "id": 1, "name": "Admin",