]> BookStack Code Mirror - bookstack/commitdiff
Page Templates: Changed template field name, added API support
authorDan Brown <redacted>
Tue, 12 Dec 2023 12:14:00 +0000 (12:14 +0000)
committerDan Brown <redacted>
Tue, 12 Dec 2023 12:14:00 +0000 (12:14 +0000)
15 files changed:
app/Entities/Controllers/BookApiController.php
app/Entities/Controllers/BookController.php
app/Entities/Controllers/PageController.php
app/Entities/Models/Book.php
app/Entities/Repos/BookRepo.php
app/Entities/Tools/TrashCan.php
database/migrations/2023_12_02_104541_add_default_template_to_books.php
dev/api/requests/books-create.json
dev/api/requests/books-update.json
dev/api/responses/books-create.json
dev/api/responses/books-read.json
dev/api/responses/books-update.json
resources/views/books/parts/form.blade.php
tests/Api/BooksApiTest.php
tests/Helpers/EntityProvider.php

index cb67184a08586681640e9968ff8d1335796ddd37..41ff11ddec3f2db68bee541c3a0aefa3eecb03b7 100644 (file)
@@ -14,11 +14,9 @@ use Illuminate\Validation\ValidationException;
 
 class BookApiController extends ApiController
 {
 
 class BookApiController extends ApiController
 {
-    protected BookRepo $bookRepo;
-
-    public function __construct(BookRepo $bookRepo)
-    {
-        $this->bookRepo = $bookRepo;
+    public function __construct(
+        protected BookRepo $bookRepo
+    ) {
     }
 
     /**
     }
 
     /**
@@ -58,7 +56,9 @@ class BookApiController extends ApiController
      */
     public function read(string $id)
     {
      */
     public function read(string $id)
     {
-        $book = Book::visible()->with(['tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy'])->findOrFail($id);
+        $book = Book::visible()
+            ->with(['tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy'])
+            ->findOrFail($id);
 
         $contents = (new BookContents($book))->getTree(true, false)->all();
         $contentsApiData = (new ApiEntityListFormatter($contents))
 
         $contents = (new BookContents($book))->getTree(true, false)->all();
         $contentsApiData = (new ApiEntityListFormatter($contents))
@@ -116,12 +116,14 @@ class BookApiController extends ApiController
                 'description' => ['string', 'max:1000'],
                 'tags'        => ['array'],
                 'image'       => array_merge(['nullable'], $this->getImageValidationRules()),
                 'description' => ['string', 'max:1000'],
                 '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()),
             ],
             'update' => [
                 'name'        => ['string', 'min:1', 'max:255'],
                 'description' => ['string', 'max:1000'],
                 'tags'        => ['array'],
                 'image'       => array_merge(['nullable'], $this->getImageValidationRules()),
+                'default_template_id' => ['nullable', 'integer'],
             ],
         ];
     }
             ],
         ];
     }
index 12df935b0a649a258e1c080fc907bb317c11a12e..faa5788938e979eab0946d440608e0417fc3fee4 100644 (file)
@@ -92,11 +92,11 @@ class BookController extends Controller
     {
         $this->checkPermission('book-create-all');
         $validated = $this->validate($request, [
     {
         $this->checkPermission('book-create-all');
         $validated = $this->validate($request, [
-            'name'              => ['required', 'string', 'max:255'],
-            'description'       => ['string', 'max:1000'],
-            'image'             => array_merge(['nullable'], $this->getImageValidationRules()),
-            'tags'              => ['array'],
-            'default_template => ['nullable', 'integer'],
+            'name'                => ['required', 'string', 'max:255'],
+            'description'         => ['string', 'max:1000'],
+            'image'               => array_merge(['nullable'], $this->getImageValidationRules()),
+            'tags'                => ['array'],
+            'default_template_id' => ['nullable', 'integer'],
         ]);
 
         $bookshelf = null;
         ]);
 
         $bookshelf = null;
@@ -167,11 +167,11 @@ class BookController extends Controller
         $this->checkOwnablePermission('book-update', $book);
 
         $validated = $this->validate($request, [
         $this->checkOwnablePermission('book-update', $book);
 
         $validated = $this->validate($request, [
-            'name'              => ['required', 'string', 'max:255'],
-            'description'       => ['string', 'max:1000'],
-            'image'             => array_merge(['nullable'], $this->getImageValidationRules()),
-            'tags'              => ['array'],
-            'default_template => ['nullable', 'integer'],
+            'name'                => ['required', 'string', 'max:255'],
+            'description'         => ['string', 'max:1000'],
+            'image'               => array_merge(['nullable'], $this->getImageValidationRules()),
+            'tags'                => ['array'],
+            'default_template_id' => ['nullable', 'integer'],
         ]);
 
         if ($request->has('image_reset')) {
         ]);
 
         if ($request->has('image_reset')) {
index d929341232a001619b74c4ee9069711f5d74afbf..0a3e76daa42bdbc69a2ce52d4b48736aa05586b1 100644 (file)
@@ -259,7 +259,7 @@ class PageController extends Controller
         $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
         $this->checkOwnablePermission('page-delete', $page);
         $this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()]));
         $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
         $this->checkOwnablePermission('page-delete', $page);
         $this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()]));
-        $usedAsTemplate = Book::query()->where('default_template', '=', $page->id)->count() > 0;
+        $usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0;
 
         return view('pages.delete', [
             'book'    => $page->book,
 
         return view('pages.delete', [
             'book'    => $page->book,
@@ -279,7 +279,7 @@ class PageController extends Controller
         $page = $this->pageRepo->getById($pageId);
         $this->checkOwnablePermission('page-update', $page);
         $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()]));
         $page = $this->pageRepo->getById($pageId);
         $this->checkOwnablePermission('page-update', $page);
         $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()]));
-        $usedAsTemplate = Book::query()->where('default_template', '=', $page->id)->count() > 0;
+        $usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0;
 
         return view('pages.delete', [
             'book'    => $page->book,
 
         return view('pages.delete', [
             'book'    => $page->book,
index faae276a5c08bd8389768b3cf9d6fa04d82bc6ca..ee9a7f44722538cf3a421add4e347d33612dd7c9 100644 (file)
@@ -15,7 +15,7 @@ use Illuminate\Support\Collection;
  *
  * @property string                                   $description
  * @property int                                      $image_id
  *
  * @property string                                   $description
  * @property int                                      $image_id
- * @property ?int                                     $default_template
+ * @property ?int                                     $default_template_id
  * @property Image|null                               $cover
  * @property \Illuminate\Database\Eloquent\Collection $chapters
  * @property \Illuminate\Database\Eloquent\Collection $pages
  * @property Image|null                               $cover
  * @property \Illuminate\Database\Eloquent\Collection $chapters
  * @property \Illuminate\Database\Eloquent\Collection $pages
@@ -78,7 +78,7 @@ class Book extends Entity implements HasCoverImage
      */
     public function defaultTemplate(): BelongsTo
     {
      */
     public function defaultTemplate(): BelongsTo
     {
-        return $this->belongsTo(Page::class, 'default_template');
+        return $this->belongsTo(Page::class, 'default_template_id');
     }
 
     /**
     }
 
     /**
index b46218fe0ee39ef6d2460d653b782b9ca142758b..03e1118b12280c9c67ef93de3a96d8d74fa98632 100644 (file)
@@ -86,6 +86,7 @@ class BookRepo
         $book = new Book();
         $this->baseRepo->create($book, $input);
         $this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
         $book = new Book();
         $this->baseRepo->create($book, $input);
         $this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
+        $this->updateBookDefaultTemplate($book, intval($input['default_template_id'] ?? null));
         Activity::add(ActivityType::BOOK_CREATE, $book);
 
         return $book;
         Activity::add(ActivityType::BOOK_CREATE, $book);
 
         return $book;
@@ -98,8 +99,8 @@ class BookRepo
     {
         $this->baseRepo->update($book, $input);
 
     {
         $this->baseRepo->update($book, $input);
 
-        if (array_key_exists('default_template', $input)) {
-            $this->updateBookDefaultTemplate($book, intval($input['default_template']));
+        if (array_key_exists('default_template_id', $input)) {
+            $this->updateBookDefaultTemplate($book, intval($input['default_template_id']));
         }
 
         if (array_key_exists('image', $input)) {
         }
 
         if (array_key_exists('image', $input)) {
@@ -118,13 +119,13 @@ class BookRepo
      */
     protected function updateBookDefaultTemplate(Book $book, int $templateId): void
     {
      */
     protected function updateBookDefaultTemplate(Book $book, int $templateId): void
     {
-        $changing = $templateId !== intval($book->default_template);
+        $changing = $templateId !== intval($book->default_template_id);
         if (!$changing) {
             return;
         }
 
         if ($templateId === 0) {
         if (!$changing) {
             return;
         }
 
         if ($templateId === 0) {
-            $book->default_template = null;
+            $book->default_template_id = null;
             $book->save();
             return;
         }
             $book->save();
             return;
         }
@@ -134,7 +135,7 @@ class BookRepo
             ->where('id', '=', $templateId)
             ->exists();
 
             ->where('id', '=', $templateId)
             ->exists();
 
-        $book->default_template = $templateExists ? $templateId : null;
+        $book->default_template_id = $templateExists ? $templateId : null;
         $book->save();
     }
 
         $book->save();
     }
 
index b0c452456a06d541a97c7e301ed1d7d74b91ef13..b25103985418f637604fb751a8d8b6868aacc409 100644 (file)
@@ -203,8 +203,8 @@ class TrashCan
         }
 
         // Remove book template usages
         }
 
         // Remove book template usages
-        Book::query()->where('default_template', '=', $page->id)
-            ->update(['default_template' => null]);
+        Book::query()->where('default_template_id', '=', $page->id)
+            ->update(['default_template_id' => null]);
 
         $page->forceDelete();
 
 
         $page->forceDelete();
 
index 913361dcbcf746d55c994a28dc1979e30575b155..c23bebc2e63c0d4f3a28c60e393739b64f8c9acc 100644 (file)
@@ -14,7 +14,7 @@ class AddDefaultTemplateToBooks extends Migration
     public function up()
     {
         Schema::table('books', function (Blueprint $table) {
     public function up()
     {
         Schema::table('books', function (Blueprint $table) {
-            $table->integer('default_template')->nullable()->default(null);
+            $table->integer('default_template_id')->nullable()->default(null);
         });
     }
 
         });
     }
 
@@ -26,7 +26,7 @@ class AddDefaultTemplateToBooks extends Migration
     public function down()
     {
         Schema::table('books', function (Blueprint $table) {
     public function down()
     {
         Schema::table('books', function (Blueprint $table) {
-            $table->dropColumn('default_template');
+            $table->dropColumn('default_template_id');
         });
     }
 }
         });
     }
 }
index 4a66266196be777e678754162ea106a8dd7ee6ee..2a38dba8392fda308cdf460a45e159bd74853bce 100644 (file)
@@ -1,4 +1,9 @@
 {
   "name": "My own book",
 {
   "name": "My own book",
-  "description": "This is my own little book"
+  "description": "This is my own little book",
+  "default_template_id": 12,
+  "tags": [
+    {"name": "Category", "value": "Top Content"},
+    {"name": "Rating", "value": "Highest"}
+  ]
 }
\ No newline at end of file
 }
\ No newline at end of file
index fc67d5fccdd2a90241ef088952201a6bb0548456..c026b7b4943f549534f224732a01f0fec26e6c6a 100644 (file)
@@ -1,4 +1,8 @@
 {
   "name": "My updated book",
 {
   "name": "My updated book",
-  "description": "This is my book with updated details"
+  "description": "This is my book with updated details",
+  "default_template_id": 12,
+  "tags": [
+    {"name": "Subject", "value": "Updates"}
+  ]
 }
\ No newline at end of file
 }
\ No newline at end of file
index 12a3e9e9fcd238631a7a3d4508e4c9027a3337a9..773879125356cfca262a340ce4d42325a2ce98ca 100644 (file)
@@ -6,6 +6,7 @@
   "created_by": 1,
   "updated_by": 1,
   "owned_by": 1,
   "created_by": 1,
   "updated_by": 1,
   "owned_by": 1,
+  "default_template_id": 12,
   "updated_at": "2020-01-12T14:05:11.000000Z",
   "created_at": "2020-01-12T14:05:11.000000Z"
 }
\ No newline at end of file
   "updated_at": "2020-01-12T14:05:11.000000Z",
   "created_at": "2020-01-12T14:05:11.000000Z"
 }
\ No newline at end of file
index 3744445d0509c7ab9de3b8ba01f3cbb2f36c48a6..21e1829b8eb4215eda4d046156b4ea5a637a6b78 100644 (file)
@@ -20,6 +20,7 @@
     "name": "Admin",
     "slug": "admin"
   },
     "name": "Admin",
     "slug": "admin"
   },
+  "default_template_id": null,
   "contents": [
     {
       "id": 50,
   "contents": [
     {
       "id": 50,
index 7d3d6735e1ecaa9efea5c39c3da88cf16b5e2dd4..f69677c4ad79d3f75d89a4cedd5c3e415d3f9685 100644 (file)
@@ -1,11 +1,12 @@
 {
   "id": 16,
 {
   "id": 16,
-  "name": "My own book",
-  "slug": "my-own-book",
-  "description": "This is my own little book - updated",
+  "name": "My updated book",
+  "slug": "my-updated-book",
+  "description": "This is my book with updated details",
   "created_at": "2020-01-12T14:09:59.000000Z",
   "updated_at": "2020-01-12T14:16:10.000000Z",
   "created_by": 1,
   "updated_by": 1,
   "created_at": "2020-01-12T14:09:59.000000Z",
   "updated_at": "2020-01-12T14:16:10.000000Z",
   "created_by": 1,
   "updated_by": 1,
-  "owned_by": 1
+  "owned_by": 1,
+  "default_template_id": 12
 }
\ No newline at end of file
 }
\ No newline at end of file
index b16468a09c49456bcfa6945c95612f4e4fc1deb4..b4ca2fba5ead75d7678571f2a8d17b6ce9a35312 100644 (file)
@@ -47,9 +47,9 @@
 
 
             @include('form.page-picker', [
 
 
             @include('form.page-picker', [
-                'name' => 'default_template',
+                'name' => 'default_template_id',
                 'placeholder' => trans('entities.books_default_template_select'),
                 'placeholder' => trans('entities.books_default_template_select'),
-                'value' => $book?->default_template ?? null,
+                'value' => $book?->default_template_id ?? null,
             ])
         </div>
 
             ])
         </div>
 
index 326304d6f1141d9c33097c93f1412bffd1f9edc9..c648faaf2f463977ad6cd2977c005fd6d488c2d7 100644 (file)
@@ -31,13 +31,16 @@ class BooksApiTest extends TestCase
     public function test_create_endpoint()
     {
         $this->actingAsApiEditor();
     public function test_create_endpoint()
     {
         $this->actingAsApiEditor();
+        $templatePage = $this->entities->templatePage();
         $details = [
             'name'        => 'My API book',
             'description' => 'A book created via the API',
         $details = [
             'name'        => 'My API book',
             'description' => 'A book created via the API',
+            'default_template_id' => $templatePage->id,
         ];
 
         $resp = $this->postJson($this->baseEndpoint, $details);
         $resp->assertStatus(200);
         ];
 
         $resp = $this->postJson($this->baseEndpoint, $details);
         $resp->assertStatus(200);
+
         $newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first();
         $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug]));
         $this->assertActivityExists('book_create', $newItem);
         $newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first();
         $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug]));
         $this->assertActivityExists('book_create', $newItem);
@@ -83,6 +86,7 @@ class BooksApiTest extends TestCase
             'owned_by' => [
                 'name' => $book->ownedBy->name,
             ],
             'owned_by' => [
                 'name' => $book->ownedBy->name,
             ],
+            'default_template_id' => null,
         ]);
     }
 
         ]);
     }
 
@@ -121,9 +125,11 @@ class BooksApiTest extends TestCase
     {
         $this->actingAsApiEditor();
         $book = $this->entities->book();
     {
         $this->actingAsApiEditor();
         $book = $this->entities->book();
+        $templatePage = $this->entities->templatePage();
         $details = [
             'name'        => 'My updated API book',
             'description' => 'A book created via the API',
         $details = [
             'name'        => 'My updated API book',
             'description' => 'A book created via the API',
+            'default_template_id' => $templatePage->id,
         ];
 
         $resp = $this->putJson($this->baseEndpoint . "/{$book->id}", $details);
         ];
 
         $resp = $this->putJson($this->baseEndpoint . "/{$book->id}", $details);
index 3cb8c44d32ca75c095cae6b73d49b6d7bf6bde20..982063421453139c95470d4ac637a45f55f2b63e 100644 (file)
@@ -53,6 +53,15 @@ class EntityProvider
         return $this->page(fn(Builder $query) => $query->where('chapter_id', '=', 0));
     }
 
         return $this->page(fn(Builder $query) => $query->where('chapter_id', '=', 0));
     }
 
+    public function templatePage(): Page
+    {
+        $page = $this->page();
+        $page->template = true;
+        $page->save();
+
+        return $page;
+    }
+
     /**
      * Get an un-fetched chapter from the system.
      */
     /**
      * Get an un-fetched chapter from the system.
      */