Rewrote book children query
This commit is contained in:
parent
bab27462ab
commit
65796cfc7b
|
@ -22,6 +22,7 @@ class BookController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BookController constructor.
|
* BookController constructor.
|
||||||
|
* @param EntityRepo $entityRepo
|
||||||
* @param BookRepo $bookRepo
|
* @param BookRepo $bookRepo
|
||||||
* @param PageRepo $pageRepo
|
* @param PageRepo $pageRepo
|
||||||
* @param ChapterRepo $chapterRepo
|
* @param ChapterRepo $chapterRepo
|
||||||
|
|
|
@ -93,47 +93,32 @@ class BookRepo extends EntityRepo
|
||||||
*/
|
*/
|
||||||
public function getChildren(Book $book, $filterDrafts = false)
|
public function getChildren(Book $book, $filterDrafts = false)
|
||||||
{
|
{
|
||||||
$pageQuery = $book->pages()->where('chapter_id', '=', 0);
|
$q = $this->permissionService->bookChildrenQuery($book->id, $filterDrafts);
|
||||||
$pageQuery = $this->permissionService->enforcePageRestrictions($pageQuery, 'view');
|
$entities = [];
|
||||||
|
$parents = [];
|
||||||
|
$tree = [];
|
||||||
|
|
||||||
if ($filterDrafts) {
|
foreach ($q as $index => $rawEntity) {
|
||||||
$pageQuery = $pageQuery->where('draft', '=', false);
|
if ($rawEntity->entity_type === 'Bookstack\\Page') {
|
||||||
}
|
$entities[$index] = $this->page->newFromBuilder($rawEntity);
|
||||||
|
} else if ($rawEntity->entity_type === 'Bookstack\\Chapter') {
|
||||||
$pages = $pageQuery->get();
|
$entities[$index] = $this->chapter->newFromBuilder($rawEntity);
|
||||||
|
$key = $entities[$index]->entity_type . ':' . $entities[$index]->id;
|
||||||
$chapterQuery = $book->chapters()->with(['pages' => function ($query) use ($filterDrafts) {
|
$parents[$key] = $entities[$index];
|
||||||
$this->permissionService->enforcePageRestrictions($query, 'view');
|
$parents[$key]->setAttribute('pages', collect());
|
||||||
if ($filterDrafts) $query->where('draft', '=', false);
|
|
||||||
}]);
|
|
||||||
$chapterQuery = $this->permissionService->enforceChapterRestrictions($chapterQuery, 'view');
|
|
||||||
$chapters = $chapterQuery->get();
|
|
||||||
$children = $pages->values();
|
|
||||||
foreach ($chapters as $chapter) {
|
|
||||||
$children->push($chapter);
|
|
||||||
}
|
|
||||||
$bookSlug = $book->slug;
|
|
||||||
|
|
||||||
$children->each(function ($child) use ($bookSlug) {
|
|
||||||
$child->setAttribute('bookSlug', $bookSlug);
|
|
||||||
if ($child->isA('chapter')) {
|
|
||||||
$child->pages->each(function ($page) use ($bookSlug) {
|
|
||||||
$page->setAttribute('bookSlug', $bookSlug);
|
|
||||||
});
|
|
||||||
$child->pages = $child->pages->sortBy(function ($child, $key) {
|
|
||||||
$score = $child->priority;
|
|
||||||
if ($child->draft) $score -= 100;
|
|
||||||
return $score;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
if ($entities[$index]->chapter_id === 0) $tree[] = $entities[$index];
|
||||||
|
$entities[$index]->book = $book;
|
||||||
|
}
|
||||||
|
|
||||||
// Sort items with drafts first then by priority.
|
foreach ($entities as $entity) {
|
||||||
return $children->sortBy(function ($child, $key) {
|
if ($entity->chapter_id === 0) continue;
|
||||||
$score = $child->priority;
|
$parentKey = 'Bookstack\\Chapter:' . $entity->chapter_id;
|
||||||
if ($child->isA('page') && $child->draft) $score -= 100;
|
$chapter = $parents[$parentKey];
|
||||||
return $score;
|
$chapter->pages->push($entity);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
return collect($tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,7 +7,6 @@ use BookStack\Exceptions\NotFoundException;
|
||||||
use BookStack\Page;
|
use BookStack\Page;
|
||||||
use BookStack\Services\PermissionService;
|
use BookStack\Services\PermissionService;
|
||||||
use BookStack\Services\ViewService;
|
use BookStack\Services\ViewService;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class EntityRepo
|
class EntityRepo
|
||||||
|
@ -127,6 +126,7 @@ class EntityRepo
|
||||||
public function getBySlug($type, $slug, $bookSlug = false)
|
public function getBySlug($type, $slug, $bookSlug = false)
|
||||||
{
|
{
|
||||||
$q = $this->entityQuery($type)->where('slug', '=', $slug);
|
$q = $this->entityQuery($type)->where('slug', '=', $slug);
|
||||||
|
|
||||||
if (strtolower($type) === 'chapter' || strtolower($type) === 'page') {
|
if (strtolower($type) === 'chapter' || strtolower($type) === 'page') {
|
||||||
$q = $q->where('book_id', '=', function($query) use ($bookSlug) {
|
$q = $q->where('book_id', '=', function($query) use ($bookSlug) {
|
||||||
$query->select('id')
|
$query->select('id')
|
||||||
|
|
|
@ -114,7 +114,7 @@ class ActivityService
|
||||||
|
|
||||||
$activity = $this->permissionService
|
$activity = $this->permissionService
|
||||||
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
|
->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
|
||||||
->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get();
|
->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * $page)->take($count)->get();
|
||||||
|
|
||||||
return $this->filterSimilar($activity);
|
return $this->filterSimilar($activity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use BookStack\Ownable;
|
||||||
use BookStack\Page;
|
use BookStack\Page;
|
||||||
use BookStack\Role;
|
use BookStack\Role;
|
||||||
use BookStack\User;
|
use BookStack\User;
|
||||||
|
use Illuminate\Database\Connection;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
@ -23,6 +24,8 @@ class PermissionService
|
||||||
public $chapter;
|
public $chapter;
|
||||||
public $page;
|
public $page;
|
||||||
|
|
||||||
|
protected $db;
|
||||||
|
|
||||||
protected $jointPermission;
|
protected $jointPermission;
|
||||||
protected $role;
|
protected $role;
|
||||||
|
|
||||||
|
@ -31,18 +34,21 @@ class PermissionService
|
||||||
/**
|
/**
|
||||||
* PermissionService constructor.
|
* PermissionService constructor.
|
||||||
* @param JointPermission $jointPermission
|
* @param JointPermission $jointPermission
|
||||||
|
* @param Connection $db
|
||||||
* @param Book $book
|
* @param Book $book
|
||||||
* @param Chapter $chapter
|
* @param Chapter $chapter
|
||||||
* @param Page $page
|
* @param Page $page
|
||||||
* @param Role $role
|
* @param Role $role
|
||||||
*/
|
*/
|
||||||
public function __construct(JointPermission $jointPermission, Book $book, Chapter $chapter, Page $page, Role $role)
|
public function __construct(JointPermission $jointPermission, Connection $db, Book $book, Chapter $chapter, Page $page, Role $role)
|
||||||
{
|
{
|
||||||
|
$this->db = $db;
|
||||||
$this->jointPermission = $jointPermission;
|
$this->jointPermission = $jointPermission;
|
||||||
$this->role = $role;
|
$this->role = $role;
|
||||||
$this->book = $book;
|
$this->book = $book;
|
||||||
$this->chapter = $chapter;
|
$this->chapter = $chapter;
|
||||||
$this->page = $page;
|
$this->page = $page;
|
||||||
|
// TODO - Update so admin still goes through filters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,6 +308,10 @@ class PermissionService
|
||||||
$explodedAction = explode('-', $action);
|
$explodedAction = explode('-', $action);
|
||||||
$restrictionAction = end($explodedAction);
|
$restrictionAction = end($explodedAction);
|
||||||
|
|
||||||
|
if ($role->system_name === 'admin') {
|
||||||
|
return $this->createJointPermissionDataArray($entity, $role, $action, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
if ($entity->isA('book')) {
|
if ($entity->isA('book')) {
|
||||||
|
|
||||||
if (!$entity->restricted) {
|
if (!$entity->restricted) {
|
||||||
|
@ -461,6 +471,51 @@ class PermissionService
|
||||||
return $q;
|
return $q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function bookChildrenQuery($book_id, $filterDrafts = false) {
|
||||||
|
|
||||||
|
// Draft setup
|
||||||
|
$params = [
|
||||||
|
'userId' => $this->currentUser()->id,
|
||||||
|
'bookIdPage' => $book_id,
|
||||||
|
'bookIdChapter' => $book_id
|
||||||
|
];
|
||||||
|
if (!$filterDrafts) {
|
||||||
|
$params['userIdDrafts'] = $this->currentUser()->id;
|
||||||
|
}
|
||||||
|
// Role setup
|
||||||
|
$userRoles = $this->getRoles();
|
||||||
|
$roleBindings = [];
|
||||||
|
$roleValues = [];
|
||||||
|
foreach ($userRoles as $index => $roleId) {
|
||||||
|
$roleBindings[':role'.$index] = $roleId;
|
||||||
|
$roleValues['role'.$index] = $roleId;
|
||||||
|
}
|
||||||
|
// TODO - Clean this up, Maybe extract into a nice class for doing these kind of manual things
|
||||||
|
// Something which will handle the above role crap in a nice clean way
|
||||||
|
$roleBindingString = implode(',', array_keys($roleBindings));
|
||||||
|
$query = "SELECT * from (
|
||||||
|
(SELECT 'Bookstack\\\Page' as entity_type, id, slug, name, text, '' as description, book_id, priority, chapter_id, draft FROM {$this->page->getTable()}
|
||||||
|
where book_id = :bookIdPage AND ". ($filterDrafts ? '(draft = 0)' : '(draft = 0 OR (draft = 1 AND created_by = :userIdDrafts))') .")
|
||||||
|
UNION
|
||||||
|
(SELECT 'Bookstack\\\Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft FROM {$this->chapter->getTable()} WHERE book_id = :bookIdChapter)
|
||||||
|
) as U WHERE (
|
||||||
|
SELECT COUNT(*) FROM {$this->jointPermission->getTable()} jp
|
||||||
|
WHERE
|
||||||
|
jp.entity_id=U.id AND
|
||||||
|
jp.entity_type=U.entity_type AND
|
||||||
|
jp.action = 'view' AND
|
||||||
|
jp.role_id IN ({$roleBindingString}) AND
|
||||||
|
(
|
||||||
|
jp.has_permission = 1 OR
|
||||||
|
(jp.has_permission_own = 1 AND jp.created_by = :userId)
|
||||||
|
)
|
||||||
|
) > 0
|
||||||
|
ORDER BY draft desc, priority asc";
|
||||||
|
|
||||||
|
$this->clean();
|
||||||
|
return $this->db->select($query, array_replace($roleValues, $params));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add restrictions for a page query
|
* Add restrictions for a page query
|
||||||
* @param $query
|
* @param $query
|
||||||
|
@ -608,7 +663,7 @@ class PermissionService
|
||||||
private function isAdmin()
|
private function isAdmin()
|
||||||
{
|
{
|
||||||
if ($this->isAdminUser === null) {
|
if ($this->isAdminUser === null) {
|
||||||
$this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasRole('admin') : false;
|
$this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasSystemRole('admin') : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->isAdminUser;
|
return $this->isAdminUser;
|
||||||
|
|
|
@ -37,7 +37,7 @@ class ViewService
|
||||||
|
|
||||||
// Otherwise create new view count
|
// Otherwise create new view count
|
||||||
$entity->views()->save($this->view->create([
|
$entity->views()->save($this->view->create([
|
||||||
'user_id' => user()->id,
|
'user_id' => $user->id,
|
||||||
'views' => 1
|
'views' => 1
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
|
10
app/User.php
10
app/User.php
|
@ -74,6 +74,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
return $this->roles->pluck('name')->contains($role);
|
return $this->roles->pluck('name')->contains($role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the user has a role.
|
||||||
|
* @param $role
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function hasSystemRole($role)
|
||||||
|
{
|
||||||
|
return $this->roles->pluck('system_name')->contains('admin');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all permissions belonging to a the current user.
|
* Get all permissions belonging to a the current user.
|
||||||
* @param bool $cache
|
* @param bool $cache
|
||||||
|
|
Loading…
Reference in New Issue