0
0
Fork 0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-04-12 16:08:08 +00:00

Page Templates: Changed template field name, added API support

This commit is contained in:
Dan Brown 2023-12-12 12:14:00 +00:00
parent 7ebe7d4e58
commit 4017048555
No known key found for this signature in database
GPG key ID: 46D9F943C24A2EF9
15 changed files with 67 additions and 37 deletions

View file

@ -14,11 +14,9 @@ use Illuminate\Validation\ValidationException;
class BookApiController extends ApiController class BookApiController extends ApiController
{ {
protected BookRepo $bookRepo; public function __construct(
protected BookRepo $bookRepo
public function __construct(BookRepo $bookRepo) ) {
{
$this->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(); $contents = (new BookContents($book))->getTree(true, false)->all();
$contentsApiData = (new ApiEntityListFormatter($contents)) $contentsApiData = (new ApiEntityListFormatter($contents))
@ -116,12 +116,14 @@ class BookApiController extends ApiController
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'tags' => ['array'], 'tags' => ['array'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
'default_template_id' => ['nullable', 'integer'],
], ],
'update' => [ 'update' => [
'name' => ['string', 'min:1', 'max:255'], 'name' => ['string', 'min:1', 'max:255'],
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'tags' => ['array'], 'tags' => ['array'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
'default_template_id' => ['nullable', 'integer'],
], ],
]; ];
} }

View file

@ -92,11 +92,11 @@ class BookController extends Controller
{ {
$this->checkPermission('book-create-all'); $this->checkPermission('book-create-all');
$validated = $this->validate($request, [ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
'tags' => ['array'], 'tags' => ['array'],
'default_template' => ['nullable', 'integer'], 'default_template_id' => ['nullable', 'integer'],
]); ]);
$bookshelf = null; $bookshelf = null;
@ -167,11 +167,11 @@ class BookController extends Controller
$this->checkOwnablePermission('book-update', $book); $this->checkOwnablePermission('book-update', $book);
$validated = $this->validate($request, [ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
'tags' => ['array'], 'tags' => ['array'],
'default_template' => ['nullable', 'integer'], 'default_template_id' => ['nullable', 'integer'],
]); ]);
if ($request->has('image_reset')) { if ($request->has('image_reset')) {

View file

@ -259,7 +259,7 @@ class PageController extends Controller
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
$this->checkOwnablePermission('page-delete', $page); $this->checkOwnablePermission('page-delete', $page);
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()])); $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', [ return view('pages.delete', [
'book' => $page->book, 'book' => $page->book,
@ -279,7 +279,7 @@ class PageController extends Controller
$page = $this->pageRepo->getById($pageId); $page = $this->pageRepo->getById($pageId);
$this->checkOwnablePermission('page-update', $page); $this->checkOwnablePermission('page-update', $page);
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()])); $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', [ return view('pages.delete', [
'book' => $page->book, 'book' => $page->book,

View file

@ -15,7 +15,7 @@ use Illuminate\Support\Collection;
* *
* @property string $description * @property string $description
* @property int $image_id * @property int $image_id
* @property ?int $default_template * @property ?int $default_template_id
* @property Image|null $cover * @property Image|null $cover
* @property \Illuminate\Database\Eloquent\Collection $chapters * @property \Illuminate\Database\Eloquent\Collection $chapters
* @property \Illuminate\Database\Eloquent\Collection $pages * @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');
} }
/** /**

View file

@ -86,6 +86,7 @@ class BookRepo
$book = new Book(); $book = new Book();
$this->baseRepo->create($book, $input); $this->baseRepo->create($book, $input);
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null); $this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
$this->updateBookDefaultTemplate($book, intval($input['default_template_id'] ?? null));
Activity::add(ActivityType::BOOK_CREATE, $book); Activity::add(ActivityType::BOOK_CREATE, $book);
return $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)) { if (array_key_exists('default_template_id', $input)) {
$this->updateBookDefaultTemplate($book, intval($input['default_template'])); $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) { if (!$changing) {
return; return;
} }
if ($templateId === 0) { if ($templateId === 0) {
$book->default_template = null; $book->default_template_id = null;
$book->save(); $book->save();
return; return;
} }
@ -134,7 +135,7 @@ class BookRepo
->where('id', '=', $templateId) ->where('id', '=', $templateId)
->exists(); ->exists();
$book->default_template = $templateExists ? $templateId : null; $book->default_template_id = $templateExists ? $templateId : null;
$book->save(); $book->save();
} }

View file

@ -203,8 +203,8 @@ class TrashCan
} }
// Remove book template usages // Remove book template usages
Book::query()->where('default_template', '=', $page->id) Book::query()->where('default_template_id', '=', $page->id)
->update(['default_template' => null]); ->update(['default_template_id' => null]);
$page->forceDelete(); $page->forceDelete();

View file

@ -14,7 +14,7 @@ class AddDefaultTemplateToBooks extends Migration
public function up() public function up()
{ {
Schema::table('books', function (Blueprint $table) { 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() public function down()
{ {
Schema::table('books', function (Blueprint $table) { Schema::table('books', function (Blueprint $table) {
$table->dropColumn('default_template'); $table->dropColumn('default_template_id');
}); });
} }
} }

View 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"}
]
} }

View 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"}
]
} }

View file

@ -6,6 +6,7 @@
"created_by": 1, "created_by": 1,
"updated_by": 1, "updated_by": 1,
"owned_by": 1, "owned_by": 1,
"default_template_id": 12,
"updated_at": "2020-01-12T14:05:11.000000Z", "updated_at": "2020-01-12T14:05:11.000000Z",
"created_at": "2020-01-12T14:05:11.000000Z" "created_at": "2020-01-12T14:05:11.000000Z"
} }

View file

@ -20,6 +20,7 @@
"name": "Admin", "name": "Admin",
"slug": "admin" "slug": "admin"
}, },
"default_template_id": null,
"contents": [ "contents": [
{ {
"id": 50, "id": 50,

View file

@ -1,11 +1,12 @@
{ {
"id": 16, "id": 16,
"name": "My own book", "name": "My updated book",
"slug": "my-own-book", "slug": "my-updated-book",
"description": "This is my own little book - updated", "description": "This is my book with updated details",
"created_at": "2020-01-12T14:09:59.000000Z", "created_at": "2020-01-12T14:09:59.000000Z",
"updated_at": "2020-01-12T14:16:10.000000Z", "updated_at": "2020-01-12T14:16:10.000000Z",
"created_by": 1, "created_by": 1,
"updated_by": 1, "updated_by": 1,
"owned_by": 1 "owned_by": 1,
"default_template_id": 12
} }

View 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>

View file

@ -31,13 +31,16 @@ class BooksApiTest extends TestCase
public function test_create_endpoint() public function test_create_endpoint()
{ {
$this->actingAsApiEditor(); $this->actingAsApiEditor();
$templatePage = $this->entities->templatePage();
$details = [ $details = [
'name' => 'My API book', 'name' => 'My API book',
'description' => 'A book created via the API', 'description' => 'A book created via the API',
'default_template_id' => $templatePage->id,
]; ];
$resp = $this->postJson($this->baseEndpoint, $details); $resp = $this->postJson($this->baseEndpoint, $details);
$resp->assertStatus(200); $resp->assertStatus(200);
$newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); $newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first();
$resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug])); $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug]));
$this->assertActivityExists('book_create', $newItem); $this->assertActivityExists('book_create', $newItem);
@ -83,6 +86,7 @@ class BooksApiTest extends TestCase
'owned_by' => [ 'owned_by' => [
'name' => $book->ownedBy->name, 'name' => $book->ownedBy->name,
], ],
'default_template_id' => null,
]); ]);
} }
@ -121,9 +125,11 @@ class BooksApiTest extends TestCase
{ {
$this->actingAsApiEditor(); $this->actingAsApiEditor();
$book = $this->entities->book(); $book = $this->entities->book();
$templatePage = $this->entities->templatePage();
$details = [ $details = [
'name' => 'My updated API book', 'name' => 'My updated API book',
'description' => 'A book created via the API', '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);

View 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.
*/ */