'
];
}
}
diff --git a/database/migrations/2023_12_17_140913_add_description_html_to_entities.php b/database/migrations/2023_12_17_140913_add_description_html_to_entities.php
new file mode 100644
index 00000000000..68c52e81be5
--- /dev/null
+++ b/database/migrations/2023_12_17_140913_add_description_html_to_entities.php
@@ -0,0 +1,36 @@
+ $table->text('description_html');
+
+ Schema::table('books', $addColumn);
+ Schema::table('chapters', $addColumn);
+ Schema::table('bookshelves', $addColumn);
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ $removeColumn = fn(Blueprint $table) => $table->removeColumn('description_html');
+
+ Schema::table('books', $removeColumn);
+ Schema::table('chapters', $removeColumn);
+ Schema::table('bookshelves', $removeColumn);
+ }
+};
diff --git a/database/seeders/DummyContentSeeder.php b/database/seeders/DummyContentSeeder.php
index 47e8d1d7c1d..a4383be50a2 100644
--- a/database/seeders/DummyContentSeeder.php
+++ b/database/seeders/DummyContentSeeder.php
@@ -3,6 +3,7 @@
namespace Database\Seeders;
use BookStack\Api\ApiToken;
+use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
@@ -38,7 +39,7 @@ public function run()
$byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id, 'owned_by' => $editorUser->id];
- \BookStack\Entities\Models\Book::factory()->count(5)->create($byData)
+ Book::factory()->count(5)->create($byData)
->each(function ($book) use ($byData) {
$chapters = Chapter::factory()->count(3)->create($byData)
->each(function ($chapter) use ($book, $byData) {
@@ -50,7 +51,7 @@ public function run()
$book->pages()->saveMany($pages);
});
- $largeBook = \BookStack\Entities\Models\Book::factory()->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)]));
+ $largeBook = Book::factory()->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)]));
$pages = Page::factory()->count(200)->make($byData);
$chapters = Chapter::factory()->count(50)->make($byData);
$largeBook->pages()->saveMany($pages);
diff --git a/dev/api/requests/books-create.json b/dev/api/requests/books-create.json
index 2a38dba8392..71dbdcc658d 100644
--- a/dev/api/requests/books-create.json
+++ b/dev/api/requests/books-create.json
@@ -1,7 +1,7 @@
{
"name": "My own book",
- "description": "This is my own little book",
- "default_template_id": 12,
+ "description_html": "
This is my own little book created via the API
",
+ "default_template_id": 2427,
"tags": [
{"name": "Category", "value": "Top Content"},
{"name": "Rating", "value": "Highest"}
diff --git a/dev/api/requests/books-update.json b/dev/api/requests/books-update.json
index c026b7b4943..30ce7e95af4 100644
--- a/dev/api/requests/books-update.json
+++ b/dev/api/requests/books-update.json
@@ -1,7 +1,7 @@
{
"name": "My updated book",
- "description": "This is my book with updated details",
- "default_template_id": 12,
+ "description_html": "
This is my book with updated details
",
+ "default_template_id": 2427,
"tags": [
{"name": "Subject", "value": "Updates"}
]
diff --git a/dev/api/requests/chapters-create.json b/dev/api/requests/chapters-create.json
index a7a0e072c6c..e9d9033874e 100644
--- a/dev/api/requests/chapters-create.json
+++ b/dev/api/requests/chapters-create.json
@@ -1,7 +1,7 @@
{
"book_id": 1,
"name": "My fantastic new chapter",
- "description": "This is a great new chapter that I've created via the API",
+ "description_html": "
This is a great new chapter that I've created via the API
",
"priority": 15,
"tags": [
{"name": "Category", "value": "Top Content"},
diff --git a/dev/api/requests/chapters-update.json b/dev/api/requests/chapters-update.json
index 18c40301b6d..be675772bc6 100644
--- a/dev/api/requests/chapters-update.json
+++ b/dev/api/requests/chapters-update.json
@@ -1,7 +1,7 @@
{
"book_id": 1,
"name": "My fantastic updated chapter",
- "description": "This is an updated chapter that I've altered via the API",
+ "description_html": "
This is an updated chapter that I've altered via the API
",
"priority": 16,
"tags": [
{"name": "Category", "value": "Kinda Good Content"},
diff --git a/dev/api/requests/shelves-create.json b/dev/api/requests/shelves-create.json
index 39b88af7e00..8f35340f65d 100644
--- a/dev/api/requests/shelves-create.json
+++ b/dev/api/requests/shelves-create.json
@@ -1,5 +1,8 @@
{
"name": "My shelf",
- "description": "This is my shelf with some books",
- "books": [5,1,3]
+ "description_html": "
This is my shelf with some books
",
+ "books": [5,1,3],
+ "tags": [
+ {"name": "Category", "value": "Learning"}
+ ]
}
\ No newline at end of file
diff --git a/dev/api/requests/shelves-update.json b/dev/api/requests/shelves-update.json
index df5f5735de0..081c8f4c1f0 100644
--- a/dev/api/requests/shelves-update.json
+++ b/dev/api/requests/shelves-update.json
@@ -1,5 +1,5 @@
{
"name": "My updated shelf",
- "description": "This is my update shelf with some books",
+ "description_html": "
This is my updated shelf with some books
",
"books": [5,1,3]
}
\ No newline at end of file
diff --git a/dev/api/responses/books-create.json b/dev/api/responses/books-create.json
index 77387912535..8895fb854d4 100644
--- a/dev/api/responses/books-create.json
+++ b/dev/api/responses/books-create.json
@@ -1,12 +1,26 @@
{
- "id": 15,
- "name": "My new book",
- "slug": "my-new-book",
- "description": "This is a book created via the API",
+ "id": 226,
+ "name": "My own book",
+ "slug": "my-own-book",
+ "description": "This is my own little book created via the API",
+ "created_at": "2023-12-22T14:22:28.000000Z",
+ "updated_at": "2023-12-22T14:22:28.000000Z",
"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"
+ "default_template_id": 2427,
+ "description_html": "
This is my<\/strong> own little book created via the API<\/p>",
+ "tags": [
+ {
+ "name": "Category",
+ "value": "Top Content",
+ "order": 0
+ },
+ {
+ "name": "Rating",
+ "value": "Highest",
+ "order": 0
+ }
+ ],
+ "cover": null
}
\ No newline at end of file
diff --git a/dev/api/responses/books-read.json b/dev/api/responses/books-read.json
index 21e1829b8eb..afeebade619 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 book with updated<\/em> details<\/p>",
+ "tags": [
+ {
+ "name": "Subject",
+ "value": "Updates",
+ "order": 0
+ }
+ ],
+ "cover": null
}
\ No newline at end of file
diff --git a/dev/api/responses/chapters-create.json b/dev/api/responses/chapters-create.json
index cf47b123df7..183186b0b42 100644
--- a/dev/api/responses/chapters-create.json
+++ b/dev/api/responses/chapters-create.json
@@ -1,15 +1,16 @@
{
- "id": 74,
+ "id": 668,
"book_id": 1,
"slug": "my-fantastic-new-chapter",
"name": "My fantastic new chapter",
"description": "This is a great new chapter that I've created via the API",
"priority": 15,
+ "created_at": "2023-12-22T14:26:28.000000Z",
+ "updated_at": "2023-12-22T14:26:28.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1,
- "updated_at": "2020-05-22T22:59:55.000000Z",
- "created_at": "2020-05-22T22:59:55.000000Z",
+ "description_html": "
This is a great new chapter<\/strong> that I've created via the API<\/p>",
"tags": [
{
"name": "Category",
@@ -19,7 +20,7 @@
{
"name": "Rating",
"value": "Highest",
- "order": 1
+ "order": 0
}
]
}
\ No newline at end of file
diff --git a/dev/api/responses/chapters-read.json b/dev/api/responses/chapters-read.json
index 5f4de85f107..192ffce7cd2 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.
This is an updated chapter<\/strong> that I've altered via the API<\/p>",
"tags": [
{
"name": "Category",
@@ -20,7 +20,7 @@
{
"name": "Rating",
"value": "Medium",
- "order": 1
+ "order": 0
}
]
}
\ No newline at end of file
diff --git a/dev/api/responses/shelves-create.json b/dev/api/responses/shelves-create.json
index 84caf8bdc86..23555783470 100644
--- a/dev/api/responses/shelves-create.json
+++ b/dev/api/responses/shelves-create.json
@@ -1,11 +1,20 @@
{
- "id": 14,
+ "id": 20,
"name": "My shelf",
"slug": "my-shelf",
"description": "This is my shelf with some books",
"created_by": 1,
"updated_by": 1,
+ "created_at": "2023-12-22T14:33:52.000000Z",
+ "updated_at": "2023-12-22T14:33:52.000000Z",
"owned_by": 1,
- "created_at": "2020-04-10T13:24:09.000000Z",
- "updated_at": "2020-04-10T13:24:09.000000Z"
+ "description_html": "
This is my shelf<\/strong> with some books<\/p>",
+ "tags": [
+ {
+ "name": "Category",
+ "value": "Learning",
+ "order": 0
+ }
+ ],
+ "cover": null
}
\ No newline at end of file
diff --git a/dev/api/responses/shelves-read.json b/dev/api/responses/shelves-read.json
index 802045bd832..eca06a46b32 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",
diff --git a/dev/api/responses/shelves-update.json b/dev/api/responses/shelves-update.json
index e199d8d68a5..3b3f0538e68 100644
--- a/dev/api/responses/shelves-update.json
+++ b/dev/api/responses/shelves-update.json
@@ -1,11 +1,20 @@
{
- "id": 14,
+ "id": 20,
"name": "My updated shelf",
"slug": "my-updated-shelf",
- "description": "This is my update shelf with some books",
+ "description": "This is my updated shelf with some books",
"created_by": 1,
"updated_by": 1,
+ "created_at": "2023-12-22T14:33:52.000000Z",
+ "updated_at": "2023-12-22T14:35:00.000000Z",
"owned_by": 1,
- "created_at": "2020-04-10T13:24:09.000000Z",
- "updated_at": "2020-04-10T13:48:22.000000Z"
+ "description_html": "
@@ -62,4 +66,5 @@
{{ trans('entities.books_save') }}
-@include('entities.selector-popup', ['entityTypes' => 'page', 'selectorEndpoint' => '/search/entity-selector-templates'])
\ No newline at end of file
+@include('entities.selector-popup')
+@include('form.editor-translations')
\ No newline at end of file
diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php
index 8f7c3f6cf11..dbb09fc9e87 100644
--- a/resources/views/books/show.blade.php
+++ b/resources/views/books/show.blade.php
@@ -26,7 +26,7 @@
+
+@include('entities.selector-popup')
+@include('form.editor-translations')
\ No newline at end of file
diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php
index 0e5224d5478..45e43ad96a9 100644
--- a/resources/views/chapters/show.blade.php
+++ b/resources/views/chapters/show.blade.php
@@ -24,7 +24,7 @@
{{ $chapter->name }}
-
{!! nl2br(e($chapter->description)) !!}
+
{!! $chapter->descriptionHtml() !!}
@if(count($pages) > 0)
@foreach($pages as $page)
diff --git a/resources/views/entities/meta.blade.php b/resources/views/entities/meta.blade.php
index 2298be8bb27..9d3c4b956a7 100644
--- a/resources/views/entities/meta.blade.php
+++ b/resources/views/entities/meta.blade.php
@@ -64,7 +64,7 @@
@icon('reference')
@if(count($chapter->visible_pages) > 0)
@foreach($chapter->visible_pages as $page)
diff --git a/resources/views/form/description-html-input.blade.php b/resources/views/form/description-html-input.blade.php
new file mode 100644
index 00000000000..3cf726ba489
--- /dev/null
+++ b/resources/views/form/description-html-input.blade.php
@@ -0,0 +1,8 @@
+
+@if($errors->has('description_html'))
+
{{ $errors->first('description_html') }}
+@endif
\ No newline at end of file
diff --git a/resources/views/pages/parts/editor-translations.blade.php b/resources/views/form/editor-translations.blade.php
similarity index 100%
rename from resources/views/pages/parts/editor-translations.blade.php
rename to resources/views/form/editor-translations.blade.php
diff --git a/resources/views/form/page-picker.blade.php b/resources/views/form/page-picker.blade.php
index d9810d575df..ad0a9d51671 100644
--- a/resources/views/form/page-picker.blade.php
+++ b/resources/views/form/page-picker.blade.php
@@ -1,6 +1,7 @@
{{--Depends on entity selector popup--}}
-
@endif
-@include('pages.parts.editor-translations')
\ No newline at end of file
+@include('form.editor-translations')
\ No newline at end of file
diff --git a/resources/views/settings/customization.blade.php b/resources/views/settings/customization.blade.php
index 7112ebcff64..4845e2055fc 100644
--- a/resources/views/settings/customization.blade.php
+++ b/resources/views/settings/customization.blade.php
@@ -3,7 +3,7 @@
@section('card')
+
+@include('entities.selector-popup')
+@include('form.editor-translations')
\ No newline at end of file
diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php
index 58fe1cd86b0..11baccaf463 100644
--- a/resources/views/shelves/show.blade.php
+++ b/resources/views/shelves/show.blade.php
@@ -28,7 +28,7 @@
',
+ ];
+
+ $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details);
+ $resp->assertStatus(200);
+
+ $this->assertDatabaseHas('bookshelves', array_merge($details, ['id' => $shelf->id, 'description' => 'A shelf updated via the API']));
+ }
+
public function test_update_increments_updated_date_if_only_tags_are_sent()
{
$this->actingAsApiEditor();
diff --git a/tests/Commands/UpdateUrlCommandTest.php b/tests/Commands/UpdateUrlCommandTest.php
index 280c81febd1..62c39c2741f 100644
--- a/tests/Commands/UpdateUrlCommandTest.php
+++ b/tests/Commands/UpdateUrlCommandTest.php
@@ -2,6 +2,7 @@
namespace Tests\Commands;
+use BookStack\Entities\Models\Entity;
use Illuminate\Support\Facades\Artisan;
use Symfony\Component\Console\Exception\RuntimeException;
use Tests\TestCase;
@@ -24,6 +25,28 @@ public function test_command_updates_page_content()
]);
}
+ public function test_command_updates_description_html()
+ {
+ /** @var Entity[] $models */
+ $models = [$this->entities->book(), $this->entities->chapter(), $this->entities->shelf()];
+
+ foreach ($models as $model) {
+ $model->description_html = '';
+ $model->save();
+ }
+
+ $this->artisan('bookstack:update-url https://example.com https://cats.example.com')
+ ->expectsQuestion("This will search for \"https://example.com\" in your database and replace it with \"https://cats.example.com\".\nAre you sure you want to proceed?", 'y')
+ ->expectsQuestion('This operation could cause issues if used incorrectly. Have you made a backup of your existing database?', 'y');
+
+ foreach ($models as $model) {
+ $this->assertDatabaseHas($model->getTable(), [
+ 'id' => $model->id,
+ 'description_html' => '',
+ ]);
+ }
+ }
+
public function test_command_requires_valid_url()
{
$badUrlMessage = 'The given urls are expected to be full urls starting with http:// or https://';
diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php
index c1842c175a7..fb9862931ae 100644
--- a/tests/Entity/BookShelfTest.php
+++ b/tests/Entity/BookShelfTest.php
@@ -77,8 +77,8 @@ public function test_shelves_create()
{
$booksToInclude = Book::take(2)->get();
$shelfInfo = [
- 'name' => 'My test book' . Str::random(4),
- 'description' => 'Test book description ' . Str::random(10),
+ 'name' => 'My test shelf' . Str::random(4),
+ 'description_html' => '
Test book description ' . Str::random(10) . '
',
];
$resp = $this->asEditor()->post('/shelves', array_merge($shelfInfo, [
'books' => $booksToInclude->implode('id', ','),
@@ -96,7 +96,7 @@ public function test_shelves_create()
$shelf = Bookshelf::where('name', '=', $shelfInfo['name'])->first();
$shelfPage = $this->get($shelf->getUrl());
$shelfPage->assertSee($shelfInfo['name']);
- $shelfPage->assertSee($shelfInfo['description']);
+ $shelfPage->assertSee($shelfInfo['description_html'], false);
$this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Category');
$this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Tag Value');
@@ -107,8 +107,8 @@ public function test_shelves_create()
public function test_shelves_create_sets_cover_image()
{
$shelfInfo = [
- 'name' => 'My test book' . Str::random(4),
- 'description' => 'Test book description ' . Str::random(10),
+ 'name' => 'My test shelf' . Str::random(4),
+ 'description_html' => '
Test book description ' . Str::random(10) . '
',
];
$imageFile = $this->files->uploadedImage('shelf-test.png');
@@ -174,7 +174,7 @@ public function test_shelf_view_sort_takes_action()
// Set book ordering
$this->asAdmin()->put($shelf->getUrl(), [
'books' => $books->implode('id', ','),
- 'tags' => [], 'description' => 'abc', 'name' => 'abc',
+ 'tags' => [], 'description_html' => 'abc', 'name' => 'abc',
]);
$this->assertEquals(3, $shelf->books()->count());
$shelf->refresh();
@@ -207,7 +207,7 @@ public function test_shelf_view_sorts_by_name_case_insensitively()
// Set book ordering
$this->asAdmin()->put($shelf->getUrl(), [
'books' => $books->implode('id', ','),
- 'tags' => [], 'description' => 'abc', 'name' => 'abc',
+ 'tags' => [], 'description_html' => 'abc', 'name' => 'abc',
]);
$this->assertEquals(3, $shelf->books()->count());
$shelf->refresh();
@@ -229,8 +229,8 @@ public function test_shelf_edit()
$booksToInclude = Book::take(2)->get();
$shelfInfo = [
- 'name' => 'My test book' . Str::random(4),
- 'description' => 'Test book description ' . Str::random(10),
+ 'name' => 'My test shelf' . Str::random(4),
+ 'description_html' => '
Test book description ' . Str::random(10) . '
',
];
$resp = $this->asEditor()->put($shelf->getUrl(), array_merge($shelfInfo, [
@@ -251,7 +251,7 @@ public function test_shelf_edit()
$shelfPage = $this->get($shelf->getUrl());
$shelfPage->assertSee($shelfInfo['name']);
- $shelfPage->assertSee($shelfInfo['description']);
+ $shelfPage->assertSee($shelfInfo['description_html'], false);
$this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Category');
$this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Tag Value');
@@ -270,8 +270,8 @@ public function test_shelf_create_new_book()
$testName = 'Test Book in Shelf Name';
$createBookResp = $this->asEditor()->post($shelf->getUrl('/create-book'), [
- 'name' => $testName,
- 'description' => 'Book in shelf description',
+ 'name' => $testName,
+ 'description_html' => 'Book in shelf description',
]);
$createBookResp->assertRedirect();
@@ -372,8 +372,8 @@ public function test_bookshelves_show_on_book()
{
// Create shelf
$shelfInfo = [
- 'name' => 'My test shelf' . Str::random(4),
- 'description' => 'Test shelf description ' . Str::random(10),
+ 'name' => 'My test shelf' . Str::random(4),
+ 'description_html' => '
Test shelf description ' . Str::random(10) . '
',
];
$this->asEditor()->post('/shelves', $shelfInfo);
@@ -381,8 +381,8 @@ public function test_bookshelves_show_on_book()
// Create book and add to shelf
$this->asEditor()->post($shelf->getUrl('/create-book'), [
- 'name' => 'Test book name',
- 'description' => 'Book in shelf description',
+ 'name' => 'Test book name',
+ 'description_html' => '