Allowed child entity permissions to override parent permissions
Updated elements of a page display and sidebar render to allow child permissions to work even when parent entitites have permission set. This allows a page with a 'view' permission to be viewable even when the parent book or chapter is not viewable. Fixes #366
Showing
5 changed files
with
31 additions
and
4 deletions
| ... | @@ -348,6 +348,10 @@ class EntityRepo | ... | @@ -348,6 +348,10 @@ class EntityRepo |
| 348 | foreach ($entities as $entity) { | 348 | foreach ($entities as $entity) { |
| 349 | if ($entity->chapter_id === 0 || $entity->chapter_id === '0') continue; | 349 | if ($entity->chapter_id === 0 || $entity->chapter_id === '0') continue; |
| 350 | $parentKey = 'BookStack\\Chapter:' . $entity->chapter_id; | 350 | $parentKey = 'BookStack\\Chapter:' . $entity->chapter_id; |
| 351 | + if (!isset($parents[$parentKey])) { | ||
| 352 | + $tree[] = $entity; | ||
| 353 | + continue; | ||
| 354 | + } | ||
| 351 | $chapter = $parents[$parentKey]; | 355 | $chapter = $parents[$parentKey]; |
| 352 | $chapter->pages->push($entity); | 356 | $chapter->pages->push($entity); |
| 353 | } | 357 | } | ... | ... |
| 1 | <div class="breadcrumbs"> | 1 | <div class="breadcrumbs"> |
| 2 | + @if (userCan('view', $book)) | ||
| 2 | <a href="{{ $chapter->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $chapter->book->getShortName() }}</a> | 3 | <a href="{{ $chapter->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $chapter->book->getShortName() }}</a> |
| 3 | <span class="sep">»</span> | 4 | <span class="sep">»</span> |
| 5 | + @endif | ||
| 4 | <a href="{{ $chapter->getUrl() }}" class="text-chapter text-button"><i class="zmdi zmdi-collection-bookmark"></i>{{$chapter->getShortName()}}</a> | 6 | <a href="{{ $chapter->getUrl() }}" class="text-chapter text-button"><i class="zmdi zmdi-collection-bookmark"></i>{{$chapter->getShortName()}}</a> |
| 5 | </div> | 7 | </div> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | <div class="breadcrumbs"> | 1 | <div class="breadcrumbs"> |
| 2 | - <a href="{{ $page->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $page->book->getShortName() }}</a> | 2 | + @if (userCan('view', $page->book)) |
| 3 | - @if($page->hasChapter()) | 3 | + <a href="{{ $page->book->getUrl() }}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $page->book->getShortName() }}</a> |
| 4 | <span class="sep">»</span> | 4 | <span class="sep">»</span> |
| 5 | + @endif | ||
| 6 | + @if($page->hasChapter() && userCan('view', $page->chapter)) | ||
| 5 | <a href="{{ $page->chapter->getUrl() }}" class="text-chapter text-button"> | 7 | <a href="{{ $page->chapter->getUrl() }}" class="text-chapter text-button"> |
| 6 | <i class="zmdi zmdi-collection-bookmark"></i> | 8 | <i class="zmdi zmdi-collection-bookmark"></i> |
| 7 | {{ $page->chapter->getShortName() }} | 9 | {{ $page->chapter->getShortName() }} |
| 8 | </a> | 10 | </a> |
| 11 | + <span class="sep">»</span> | ||
| 9 | @endif | 12 | @endif |
| 10 | - <span class="sep">»</span> | ||
| 11 | <a href="{{ $page->getUrl() }}" class="text-page text-button"><i class="zmdi zmdi-file"></i>{{ $page->getShortName() }}</a> | 13 | <a href="{{ $page->getUrl() }}" class="text-page text-button"><i class="zmdi zmdi-file"></i>{{ $page->getShortName() }}</a> |
| 12 | </div> | 14 | </div> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -39,8 +39,10 @@ | ... | @@ -39,8 +39,10 @@ |
| 39 | 39 | ||
| 40 | <h6 class="text-muted">{{ trans('entities.books_navigation') }}</h6> | 40 | <h6 class="text-muted">{{ trans('entities.books_navigation') }}</h6> |
| 41 | <ul class="sidebar-page-list menu"> | 41 | <ul class="sidebar-page-list menu"> |
| 42 | - <li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li> | ||
| 43 | 42 | ||
| 43 | + @if (userCan('view', $book)) | ||
| 44 | + <li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li> | ||
| 45 | + @endif | ||
| 44 | 46 | ||
| 45 | @foreach($sidebarTree as $bookChild) | 47 | @foreach($sidebarTree as $bookChild) |
| 46 | <li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}"> | 48 | <li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}"> | ... | ... |
| ... | @@ -522,4 +522,21 @@ class RestrictionsTest extends BrowserKitTest | ... | @@ -522,4 +522,21 @@ class RestrictionsTest extends BrowserKitTest |
| 522 | ->see('Delete Chapter'); | 522 | ->see('Delete Chapter'); |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | + public function test_page_visible_if_has_permissions_when_book_not_visible() | ||
| 526 | + { | ||
| 527 | + $book = \BookStack\Book::first(); | ||
| 528 | + $bookChapter = $book->chapters->first(); | ||
| 529 | + $bookPage = $bookChapter->pages->first(); | ||
| 530 | + | ||
| 531 | + $this->setEntityRestrictions($book, []); | ||
| 532 | + $this->setEntityRestrictions($bookPage, ['view']); | ||
| 533 | + | ||
| 534 | + $this->actingAs($this->viewer); | ||
| 535 | + $this->get($bookPage->getUrl()); | ||
| 536 | + $this->assertResponseOk(); | ||
| 537 | + $this->see($bookPage->name); | ||
| 538 | + $this->dontSee(substr($book->name, 0, 15)); | ||
| 539 | + $this->dontSee(substr($bookChapter->name, 0, 15)); | ||
| 540 | + } | ||
| 541 | + | ||
| 525 | } | 542 | } | ... | ... |
-
Please register or sign in to post a comment