Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions app/Entities/Controllers/ChapterApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@ class ChapterApiController extends ApiController
{
protected $rules = [
'create' => [
'book_id' => ['required', 'integer'],
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1900'],
'description_html' => ['string', 'max:2000'],
'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'],
'default_template_id' => ['nullable', 'integer'],
],
'update' => [
'book_id' => ['integer'],
'name' => ['string', 'min:1', 'max:255'],
'description' => ['string', 'max:1900'],
'description_html' => ['string', 'max:2000'],
'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'],
'default_template_id' => ['nullable', 'integer'],
],
];

Expand Down
14 changes: 8 additions & 6 deletions app/Entities/Controllers/ChapterController.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ public function create(string $bookSlug)
public function store(Request $request, string $bookSlug)
{
$validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'],
'description_html' => ['string', 'max:2000'],
'tags' => ['array'],
'name' => ['required', 'string', 'max:255'],
'description_html' => ['string', 'max:2000'],
'tags' => ['array'],
'default_template_id' => ['nullable', 'integer'],
]);

$book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
Expand Down Expand Up @@ -111,9 +112,10 @@ public function edit(string $bookSlug, string $chapterSlug)
public function update(Request $request, string $bookSlug, string $chapterSlug)
{
$validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'],
'description_html' => ['string', 'max:2000'],
'tags' => ['array'],
'name' => ['required', 'string', 'max:255'],
'description_html' => ['string', 'max:2000'],
'tags' => ['array'],
'default_template_id' => ['nullable', 'integer'],
]);

$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
Expand Down
9 changes: 7 additions & 2 deletions app/Entities/Controllers/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use BookStack\Activity\Tools\CommentTree;
use BookStack\Activity\Tools\UserEntityWatchOptions;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\PageRepo;
use BookStack\Entities\Tools\BookContents;
Expand Down Expand Up @@ -259,7 +260,9 @@ public function showDelete(string $bookSlug, string $pageSlug)
$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_id', '=', $page->id)->count() > 0;
$usedAsTemplate =
Book::query()->where('default_template_id', '=', $page->id)->count() > 0 ||
Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0;

return view('pages.delete', [
'book' => $page->book,
Expand All @@ -279,7 +282,9 @@ public function showDeleteDraft(string $bookSlug, int $pageId)
$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_id', '=', $page->id)->count() > 0;
$usedAsTemplate =
Book::query()->where('default_template_id', '=', $page->id)->count() > 0 ||
Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0;

return view('pages.delete', [
'book' => $page->book,
Expand Down
11 changes: 11 additions & 0 deletions app/Entities/Models/Chapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace BookStack\Entities\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
Expand All @@ -11,6 +12,8 @@
*
* @property Collection<Page> $pages
* @property string $description
* @property ?int $default_template_id
* @property ?Page $defaultTemplate
*/
class Chapter extends BookChild
{
Expand Down Expand Up @@ -48,6 +51,14 @@ public function getUrl(string $path = ''): string
return url('/' . implode('/', $parts));
}

/**
* Get the Page that is used as default template for newly created pages within this Chapter.
*/
public function defaultTemplate(): BelongsTo
{
return $this->belongsTo(Page::class, 'default_template_id');
}

/**
* Get the visible pages in this chapter.
*/
Expand Down
34 changes: 34 additions & 0 deletions app/Entities/Repos/ChapterRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use BookStack\Activity\ActivityType;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Tools\BookContents;
Expand Down Expand Up @@ -46,6 +47,7 @@ public function create(array $input, Book $parentBook): Chapter
$chapter->book_id = $parentBook->id;
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
$this->baseRepo->create($chapter, $input);
$this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);

return $chapter;
Expand All @@ -57,6 +59,11 @@ public function create(array $input, Book $parentBook): Chapter
public function update(Chapter $chapter, array $input): Chapter
{
$this->baseRepo->update($chapter, $input);

if (array_key_exists('default_template_id', $input)) {
$this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id']));
}

Activity::add(ActivityType::CHAPTER_UPDATE, $chapter);

return $chapter;
Expand Down Expand Up @@ -101,6 +108,33 @@ public function move(Chapter $chapter, string $parentIdentifier): Book
return $parent;
}

/**
* Update the default page template used for this chapter.
* Checks that, if changing, the provided value is a valid template and the user
* has visibility of the provided page template id.
*/
protected function updateChapterDefaultTemplate(Chapter $chapter, int $templateId): void
{
$changing = $templateId !== intval($chapter->default_template_id);
if (!$changing) {
return;
}

if ($templateId === 0) {
$chapter->default_template_id = null;
$chapter->save();
return;
}

$templateExists = Page::query()->visible()
->where('template', '=', true)
->where('id', '=', $templateId)
->exists();

$chapter->default_template_id = $templateExists ? $templateId : null;
$chapter->save();
}
Comment thread
Man-in-Black marked this conversation as resolved.

/**
* Find a page parent entity via an identifier string in the format:
* {type}:{id}
Expand Down
8 changes: 7 additions & 1 deletion app/Entities/Repos/PageRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,13 @@ public function getNewDraftPage(Entity $parent)
$page->book_id = $parent->id;
}

$defaultTemplate = $page->book->defaultTemplate;
// check for chapter
if ($page->chapter_id) {
$defaultTemplate = $page->chapter->defaultTemplate;
} else {
$defaultTemplate = $page->book->defaultTemplate;
}
Comment thread
Man-in-Black marked this conversation as resolved.

if ($defaultTemplate && userCan('view', $defaultTemplate)) {
$page->forceFill([
'html' => $defaultTemplate->html,
Expand Down
4 changes: 4 additions & 0 deletions app/Entities/Tools/TrashCan.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ protected function destroyPage(Page $page): int
Book::query()->where('default_template_id', '=', $page->id)
->update(['default_template_id' => null]);

// Remove chapter template usages
Chapter::query()->where('default_template_id', '=', $page->id)
->update(['default_template_id' => null]);

$page->forceDelete();

return 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddDefaultTemplateToChapters extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('chapters', function (Blueprint $table) {
$table->integer('default_template_id')->nullable()->default(null);
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('chapters', function (Blueprint $table) {
$table->dropColumn('default_template_id');
});
}
}
8 changes: 4 additions & 4 deletions lang/en/entities.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
'export_pdf' => 'PDF File',
'export_text' => 'Plain Text File',
'export_md' => 'Markdown File',
'default_template' => 'Default Page Template',
'default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book/chapter. Keep in mind this will only be used if the page creator has view access to those chosen template page.',
'default_template_select' => 'Select a template page',

// Permissions and restrictions
'permissions' => 'Permissions',
Expand Down Expand Up @@ -132,9 +135,6 @@
'books_edit_named' => 'Edit Book :bookName',
'books_form_book_name' => 'Book Name',
'books_save' => 'Save Book',
'books_default_template' => 'Default Page Template',
'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.',
'books_default_template_select' => 'Select a template page',
'books_permissions' => 'Book Permissions',
'books_permissions_updated' => 'Book Permissions Updated',
'books_empty_contents' => 'No pages or chapters have been created for this book.',
Expand Down Expand Up @@ -207,7 +207,7 @@
'pages_delete_draft' => 'Delete Draft Page',
'pages_delete_success' => 'Page deleted',
'pages_delete_draft_success' => 'Draft page deleted',
'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.',
'pages_delete_warning_template' => 'This page is in active use as a book or chapter default page template. These books or chapters will no longer have a default page template assigned after this page is deleted.',
'pages_delete_confirm' => 'Are you sure you want to delete this page?',
'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?',
'pages_editing_named' => 'Editing Page :pageName',
Expand Down
18 changes: 2 additions & 16 deletions resources/views/books/parts/form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,10 @@

<div class="form-group collapsible" component="collapsible" id="template-control">
<button refs="collapsible@trigger" type="button" class="collapse-title text-link" aria-expanded="false">
<label for="template-manager">{{ trans('entities.books_default_template') }}</label>
<label for="template-manager">{{ trans('entities.default_template') }}</label>
</button>
<div refs="collapsible@content" class="collapse-content">
<div class="flex-container-row gap-l justify-space-between pb-xs wrap">
<p class="text-muted small my-none min-width-xs flex">
{{ trans('entities.books_default_template_explain') }}
</p>

<div class="min-width-m">
@include('form.page-picker', [
'name' => 'default_template_id',
'placeholder' => trans('entities.books_default_template_select'),
'value' => $book->default_template_id ?? null,
'selectorEndpoint' => '/search/entity-selector-templates',
])
</div>
</div>

@include('entities.template-selector', ['entity' => $book ?? null])
</div>
</div>

Expand Down
9 changes: 9 additions & 0 deletions resources/views/chapters/parts/form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
</div>
</div>

<div class="form-group collapsible" component="collapsible" id="template-control">
<button refs="collapsible@trigger" type="button" class="collapse-title text-link" aria-expanded="false">
<label for="template-manager">{{ trans('entities.default_template') }}</label>
</button>
<div refs="collapsible@content" class="collapse-content">
@include('entities.template-selector', ['entity' => $chapter ?? null])
</div>
</div>

<div class="form-group text-right">
<a href="{{ isset($chapter) ? $chapter->getUrl() : $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button">{{ trans('entities.chapters_save') }}</button>
Expand Down
14 changes: 14 additions & 0 deletions resources/views/entities/template-selector.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="flex-container-row gap-l justify-space-between pb-xs wrap">
<p class="text-muted small my-none min-width-xs flex">
{{ trans('entities.default_template_explain') }}
</p>

<div class="min-width-m">
@include('form.page-picker', [
'name' => 'default_template_id',
'placeholder' => trans('entities.default_template_select'),
'value' => $entity->default_template_id ?? null,
'selectorEndpoint' => '/search/entity-selector-templates',
])
</div>
</div>