Skip to content

Commit 70bfebc

Browse files
authored
Added Default Templates for Chapters
1 parent b191d8f commit 70bfebc

File tree

9 files changed

+131
-9
lines changed

9 files changed

+131
-9
lines changed

app/Entities/Controllers/ChapterController.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ public function create(string $bookSlug)
4949
public function store(Request $request, string $bookSlug)
5050
{
5151
$validated = $this->validate($request, [
52-
'name' => ['required', 'string', 'max:255'],
53-
'description_html' => ['string', 'max:2000'],
54-
'tags' => ['array'],
52+
'name' => ['required', 'string', 'max:255'],
53+
'description_html' => ['string', 'max:2000'],
54+
'tags' => ['array'],
55+
'default_template_id' => ['nullable', 'integer'],
5556
]);
5657

5758
$book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail();
@@ -111,9 +112,10 @@ public function edit(string $bookSlug, string $chapterSlug)
111112
public function update(Request $request, string $bookSlug, string $chapterSlug)
112113
{
113114
$validated = $this->validate($request, [
114-
'name' => ['required', 'string', 'max:255'],
115-
'description_html' => ['string', 'max:2000'],
116-
'tags' => ['array'],
115+
'name' => ['required', 'string', 'max:255'],
116+
'description_html' => ['string', 'max:2000'],
117+
'tags' => ['array'],
118+
'default_template_id' => ['nullable', 'integer'],
117119
]);
118120

119121
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);

app/Entities/Controllers/PageController.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use BookStack\Activity\Tools\CommentTree;
77
use BookStack\Activity\Tools\UserEntityWatchOptions;
88
use BookStack\Entities\Models\Book;
9+
use BookStack\Entities\Models\Chapter;
910
use BookStack\Entities\Models\Page;
1011
use BookStack\Entities\Repos\PageRepo;
1112
use BookStack\Entities\Tools\BookContents;
@@ -259,7 +260,9 @@ public function showDelete(string $bookSlug, string $pageSlug)
259260
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
260261
$this->checkOwnablePermission('page-delete', $page);
261262
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()]));
262-
$usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0;
263+
$usedAsTemplate =
264+
Book::query()->where('default_template_id', '=', $page->id)->count() > 0 ||
265+
Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0;
263266

264267
return view('pages.delete', [
265268
'book' => $page->book,
@@ -279,7 +282,9 @@ public function showDeleteDraft(string $bookSlug, int $pageId)
279282
$page = $this->pageRepo->getById($pageId);
280283
$this->checkOwnablePermission('page-update', $page);
281284
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()]));
282-
$usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0;
285+
$usedAsTemplate =
286+
Book::query()->where('default_template_id', '=', $page->id)->count() > 0 ||
287+
Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0;
283288

284289
return view('pages.delete', [
285290
'book' => $page->book,

app/Entities/Models/Chapter.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace BookStack\Entities\Models;
44

5+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
56
use Illuminate\Database\Eloquent\Factories\HasFactory;
67
use Illuminate\Database\Eloquent\Relations\HasMany;
78
use Illuminate\Support\Collection;
@@ -11,6 +12,8 @@
1112
*
1213
* @property Collection<Page> $pages
1314
* @property string $description
15+
* @property ?int $default_template_id
16+
* @property ?Page $defaultTemplate
1417
*/
1518
class Chapter extends BookChild
1619
{
@@ -48,6 +51,14 @@ public function getUrl(string $path = ''): string
4851
return url('/' . implode('/', $parts));
4952
}
5053

54+
/**
55+
* Get the Page that is used as default template for newly created pages within this Chapter.
56+
*/
57+
public function defaultTemplate(): BelongsTo
58+
{
59+
return $this->belongsTo(Page::class, 'default_template_id');
60+
}
61+
5162
/**
5263
* Get the visible pages in this chapter.
5364
*/

app/Entities/Repos/ChapterRepo.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use BookStack\Activity\ActivityType;
66
use BookStack\Entities\Models\Book;
7+
use BookStack\Entities\Models\Page;
78
use BookStack\Entities\Models\Chapter;
89
use BookStack\Entities\Models\Entity;
910
use BookStack\Entities\Tools\BookContents;
@@ -46,6 +47,7 @@ public function create(array $input, Book $parentBook): Chapter
4647
$chapter->book_id = $parentBook->id;
4748
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
4849
$this->baseRepo->create($chapter, $input);
50+
$this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
4951
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
5052

5153
return $chapter;
@@ -57,6 +59,11 @@ public function create(array $input, Book $parentBook): Chapter
5759
public function update(Chapter $chapter, array $input): Chapter
5860
{
5961
$this->baseRepo->update($chapter, $input);
62+
63+
if (array_key_exists('default_template_id', $input)) {
64+
$this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id']));
65+
}
66+
6067
Activity::add(ActivityType::CHAPTER_UPDATE, $chapter);
6168

6269
return $chapter;
@@ -101,6 +108,33 @@ public function move(Chapter $chapter, string $parentIdentifier): Book
101108
return $parent;
102109
}
103110

111+
/**
112+
* Update the default page template used for this chapter.
113+
* Checks that, if changing, the provided value is a valid template and the user
114+
* has visibility of the provided page template id.
115+
*/
116+
protected function updateChapterDefaultTemplate(Chapter $chapter, int $templateId): void
117+
{
118+
$changing = $templateId !== intval($chapter->default_template_id);
119+
if (!$changing) {
120+
return;
121+
}
122+
123+
if ($templateId === 0) {
124+
$chapter->default_template_id = null;
125+
$chapter->save();
126+
return;
127+
}
128+
129+
$templateExists = Page::query()->visible()
130+
->where('template', '=', true)
131+
->where('id', '=', $templateId)
132+
->exists();
133+
134+
$chapter->default_template_id = $templateExists ? $templateId : null;
135+
$chapter->save();
136+
}
137+
104138
/**
105139
* Find a page parent entity via an identifier string in the format:
106140
* {type}:{id}

app/Entities/Repos/PageRepo.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,13 @@ public function getNewDraftPage(Entity $parent)
136136
$page->book_id = $parent->id;
137137
}
138138

139-
$defaultTemplate = $page->book->defaultTemplate;
139+
// check for chapter
140+
if ($page->chapter_id) {
141+
$defaultTemplate = $page->chapter->defaultTemplate;
142+
} else {
143+
$defaultTemplate = $page->book->defaultTemplate;
144+
}
145+
140146
if ($defaultTemplate && userCan('view', $defaultTemplate)) {
141147
$page->forceFill([
142148
'html' => $defaultTemplate->html,

app/Entities/Tools/TrashCan.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ protected function destroyPage(Page $page): int
208208

209209
$page->forceDelete();
210210

211+
// Remove chapter template usages
212+
Chapter::query()->where('default_template_id', '=', $page->id)
213+
->update(['default_template_id' => null]);
214+
215+
$page->forceDelete();
216+
211217
return 1;
212218
}
213219

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class AddDefaultTemplateToChapters extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::table('chapters', function (Blueprint $table) {
17+
$table->integer('default_template_id')->nullable()->default(null);
18+
});
19+
}
20+
21+
/**
22+
* Reverse the migrations.
23+
*
24+
* @return void
25+
*/
26+
public function down()
27+
{
28+
Schema::table('chapters', function (Blueprint $table) {
29+
$table->dropColumn('default_template_id');
30+
});
31+
}
32+
}

lang/en/entities.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@
192192
'chapters_permissions_success' => 'Chapter Permissions Updated',
193193
'chapters_search_this' => 'Search this chapter',
194194
'chapter_sort_book' => 'Sort Book',
195+
'chapter_default_template' => 'Default Page Template',
196+
'chapter_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this chapter. Keep in mind this will only be used if the page creator has view access to those chosen template page.',
197+
'chapter_default_template_select' => 'Select a template page',
195198

196199
// Pages
197200
'page' => 'Page',

resources/views/chapters/parts/form.blade.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,29 @@
2222
</div>
2323
</div>
2424

25+
<div class="form-group collapsible" component="collapsible" id="template-control">
26+
<button refs="collapsible@trigger" type="button" class="collapse-title text-link" aria-expanded="false">
27+
<label for="template-manager">{{ trans('entities.chapter_default_template') }}</label>
28+
</button>
29+
<div refs="collapsible@content" class="collapse-content">
30+
<div class="flex-container-row gap-l justify-space-between pb-xs wrap">
31+
<p class="text-muted small my-none min-width-xs flex">
32+
{{ trans('entities.chapter_default_template_explain') }}
33+
</p>
34+
35+
<div class="min-width-m">
36+
@include('form.page-picker', [
37+
'name' => 'default_template_id',
38+
'placeholder' => trans('entities.chapter_default_template_select'),
39+
'value' => $chapter->default_template_id ?? null,
40+
'selectorEndpoint' => '/search/entity-selector-templates',
41+
])
42+
</div>
43+
</div>
44+
45+
</div>
46+
</div>
47+
2548
<div class="form-group text-right">
2649
<a href="{{ isset($chapter) ? $chapter->getUrl() : $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
2750
<button type="submit" class="button">{{ trans('entities.chapters_save') }}</button>

0 commit comments

Comments
 (0)