/**
* Class Chapter
* @property Collection<Page> $pages
- * @package BookStack\Entities
*/
class Chapter extends BookChild
{
return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description;
}
- /**
- * Check if this chapter has any child pages.
- * @return bool
- */
- public function hasChildren()
- {
- return count($this->pages) > 0;
- }
-
/**
* Get the visible pages in this chapter.
*/
$pages->groupBy('chapter_id')->each(function ($pages, $chapter_id) use ($chapterMap, &$lonePages) {
$chapter = $chapterMap->get($chapter_id);
if ($chapter) {
- $chapter->setAttribute('pages', collect($pages)->sortBy($this->bookChildSortFunc()));
+ $chapter->setAttribute('visible_pages', collect($pages)->sortBy($this->bookChildSortFunc()));
} else {
$lonePages = $lonePages->concat($pages);
}
});
+ $chapters->whereNull('visible_pages')->each(function (Chapter $chapter) {
+ $chapter->setAttribute('visible_pages', collect([]));
+ });
+
$all->each(function (Entity $entity) use ($renderPages) {
$entity->setRelation('book', $this->book);
<ul class="contents">
@foreach($bookChildren as $bookChild)
<li><a href="#{{$bookChild->getType()}}-{{$bookChild->id}}">{{ $bookChild->name }}</a></li>
- @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
+ @if($bookChild->isA('chapter') && count($bookChild->visible_pages) > 0)
<ul>
- @foreach($bookChild->pages as $page)
+ @foreach($bookChild->visible_pages as $page)
<li><a href="#page-{{$page->id}}">{{ $page->name }}</a></li>
@endforeach
</ul>
@if($bookChild->isA('chapter'))
<p>{{ $bookChild->description }}</p>
- @if(count($bookChild->pages) > 0)
- @foreach($bookChild->pages as $page)
+ @if(count($bookChild->visible_pages) > 0)
+ @foreach($bookChild->visible_pages as $page)
<div class="page-break"></div>
<div class="chapter-hint">{{$bookChild->name}}</div>
<h1 id="page-{{$page->id}}">{{ $page->name }}</h1>
</div>
@if($bookChild->isA('chapter'))
<ul>
- @foreach($bookChild->pages as $page)
+ @foreach($bookChild->visible_pages as $page)
<li class="text-page"
data-id="{{$page->id}}" data-type="page"
data-name="{{ $page->name }}" data-created="{{ $page->created_at->timestamp }}"
<div class="chapter-child-menu">
<button chapter-toggle type="button" aria-expanded="{{ $isOpen ? 'true' : 'false' }}"
class="text-muted @if($isOpen) open @endif">
- @icon('caret-right') @icon('page') <span>{{ trans_choice('entities.x_pages', $bookChild->pages->count()) }}</span>
+ @icon('caret-right') @icon('page') <span>{{ trans_choice('entities.x_pages', $bookChild->visible_pages->count()) }}</span>
</button>
<ul class="sub-menu inset-list @if($isOpen) open @endif" @if($isOpen) style="display: block;" @endif role="menu">
- @foreach($bookChild->pages as $childPage)
+ @foreach($bookChild->visible_pages as $childPage)
<li class="list-item-page {{ $childPage->isA('page') && $childPage->draft ? 'draft' : '' }}" role="presentation">
@include('partials.entity-list-item-basic', ['entity' => $childPage, 'classes' => $current->matches($childPage)? 'selected' : '' ])
</li>
-<a href="{{ $chapter->getUrl() }}" class="chapter entity-list-item @if($chapter->hasChildren()) has-children @endif" data-entity-type="chapter" data-entity-id="{{$chapter->id}}">
+{{--This view display child pages in a list if pre-loaded onto a 'visible_pages' property,--}}
+{{--To ensure that the pages have been loaded efficiently with permissions taken into account.--}}
+<a href="{{ $chapter->getUrl() }}" class="chapter entity-list-item @if($chapter->visible_pages->count() > 0) has-children @endif" data-entity-type="chapter" data-entity-id="{{$chapter->id}}">
<span class="icon text-chapter">@icon('chapter')</span>
<div class="content">
<h4 class="entity-list-item-name break-text">{{ $chapter->name }}</h4>
</div>
</div>
</a>
-@if ($chapter->hasChildren())
+@if ($chapter->visible_pages->count() > 0)
<div class="chapter chapter-expansion">
<span class="icon text-chapter">@icon('page')</span>
<div class="content">
<button type="button" chapter-toggle
aria-expanded="false"
- class="text-muted chapter-expansion-toggle">@icon('caret-right') <span>{{ trans_choice('entities.x_pages', $chapter->pages->count()) }}</span></button>
+ class="text-muted chapter-expansion-toggle">@icon('caret-right') <span>{{ trans_choice('entities.x_pages', $chapter->visible_pages->count()) }}</span></button>
<div class="inset-list">
<div class="entity-list-item-children">
- @include('partials.entity-list', ['entities' => $chapter->pages])
+ @include('partials.entity-list', ['entities' => $chapter->visible_pages])
</div>
</div>
</div>
<li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}">
@include('partials.entity-list-item-basic', ['entity' => $bookChild, 'classes' => $current->matches($bookChild)? 'selected' : ''])
- @if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
+ @if($bookChild->isA('chapter') && count($bookChild->visible_pages) > 0)
<div class="entity-list-item no-hover">
<span role="presentation" class="icon text-chapter"></span>
<div class="content">
+++ /dev/null
-<div class="page-list">
- @if(count($pages) > 0)
- @foreach($pages as $pageIndex => $page)
- <div class="anim searchResult" style="animation-delay: {{$pageIndex*50 . 'ms'}};">
- @include('pages.list-item', ['page' => $page])
- <hr>
- </div>
- @endforeach
- @else
- <p class="text-muted">{{ trans('entities.search_no_pages') }}</p>
- @endif
-</div>
-
-@if(count($chapters) > 0)
- <div class="page-list">
- @foreach($chapters as $chapterIndex => $chapter)
- <div class="anim searchResult" style="animation-delay: {{($chapterIndex+count($pages))*50 . 'ms'}};">
- @include('chapters.list-item', ['chapter' => $chapter, 'hidePages' => true])
- <hr>
- </div>
- @endforeach
- </div>
-@endif
-
->dontSee($page->name);
}
+ public function test_restricted_chapter_pages_not_visible_on_book_page()
+ {
+ $chapter = Chapter::query()->first();
+ $this->actingAs($this->user)
+ ->visit($chapter->book->getUrl())
+ ->see($chapter->pages->first()->name);
+
+ foreach ($chapter->pages as $page) {
+ $this->setEntityRestrictions($page, []);
+ }
+
+ $this->actingAs($this->user)
+ ->visit($chapter->book->getUrl())
+ ->dontSee($chapter->pages->first()->name);
+ }
+
public function test_bookshelf_update_restriction_override()
{
$shelf = Bookshelf::first();