mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-08-26 12:16:07 +00:00
Rewrote book children query
This commit is contained in:
parent
bab27462ab
commit
65796cfc7b
@ -22,6 +22,7 @@ class BookController extends Controller
|
||||
|
||||
/**
|
||||
* BookController constructor.
|
||||
* @param EntityRepo $entityRepo
|
||||
* @param BookRepo $bookRepo
|
||||
* @param PageRepo $pageRepo
|
||||
* @param ChapterRepo $chapterRepo
|
||||
|
@ -93,47 +93,32 @@ class BookRepo extends EntityRepo
|
||||
*/
|
||||
public function getChildren(Book $book, $filterDrafts = false)
|
||||
{
|
||||
$pageQuery = $book->pages()->where('chapter_id', '=', 0);
|
||||
$pageQuery = $this->permissionService->enforcePageRestrictions($pageQuery, 'view');
|
||||
$q = $this->permissionService->bookChildrenQuery($book->id, $filterDrafts);
|
||||
$entities = [];
|
||||
$parents = [];
|
||||
$tree = [];
|
||||
|
||||
if ($filterDrafts) {
|
||||
$pageQuery = $pageQuery->where('draft', '=', false);
|
||||
}
|
||||
|
||||
$pages = $pageQuery->get();
|
||||
|
||||
$chapterQuery = $book->chapters()->with(['pages' => function ($query) use ($filterDrafts) {
|
||||
$this->permissionService->enforcePageRestrictions($query, 'view');
|
||||
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;
|
||||
});
|
||||
foreach ($q as $index => $rawEntity) {
|
||||
if ($rawEntity->entity_type === 'Bookstack\\Page') {
|
||||
$entities[$index] = $this->page->newFromBuilder($rawEntity);
|
||||
} else if ($rawEntity->entity_type === 'Bookstack\\Chapter') {
|
||||
$entities[$index] = $this->chapter->newFromBuilder($rawEntity);
|
||||
$key = $entities[$index]->entity_type . ':' . $entities[$index]->id;
|
||||
$parents[$key] = $entities[$index];
|
||||
$parents[$key]->setAttribute('pages', collect());
|
||||
}
|
||||
});
|
||||
if ($entities[$index]->chapter_id === 0) $tree[] = $entities[$index];
|
||||
$entities[$index]->book = $book;
|
||||
}
|
||||
|
||||
// Sort items with drafts first then by priority.
|
||||
return $children->sortBy(function ($child, $key) {
|
||||
$score = $child->priority;
|
||||
if ($child->isA('page') && $child->draft) $score -= 100;
|
||||
return $score;
|
||||
});
|
||||
foreach ($entities as $entity) {
|
||||
if ($entity->chapter_id === 0) continue;
|
||||
$parentKey = 'Bookstack\\Chapter:' . $entity->chapter_id;
|
||||
$chapter = $parents[$parentKey];
|
||||
$chapter->pages->push($entity);
|
||||
}
|
||||
|
||||
return collect($tree);
|
||||
}
|
||||
|
||||
}
|
@ -7,7 +7,6 @@ use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Page;
|
||||
use BookStack\Services\PermissionService;
|
||||
use BookStack\Services\ViewService;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class EntityRepo
|
||||
@ -127,6 +126,7 @@ class EntityRepo
|
||||
public function getBySlug($type, $slug, $bookSlug = false)
|
||||
{
|
||||
$q = $this->entityQuery($type)->where('slug', '=', $slug);
|
||||
|
||||
if (strtolower($type) === 'chapter' || strtolower($type) === 'page') {
|
||||
$q = $q->where('book_id', '=', function($query) use ($bookSlug) {
|
||||
$query->select('id')
|
||||
|
@ -114,7 +114,7 @@ class ActivityService
|
||||
|
||||
$activity = $this->permissionService
|
||||
->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);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use BookStack\Ownable;
|
||||
use BookStack\Page;
|
||||
use BookStack\Role;
|
||||
use BookStack\User;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@ -23,6 +24,8 @@ class PermissionService
|
||||
public $chapter;
|
||||
public $page;
|
||||
|
||||
protected $db;
|
||||
|
||||
protected $jointPermission;
|
||||
protected $role;
|
||||
|
||||
@ -31,18 +34,21 @@ class PermissionService
|
||||
/**
|
||||
* PermissionService constructor.
|
||||
* @param JointPermission $jointPermission
|
||||
* @param Connection $db
|
||||
* @param Book $book
|
||||
* @param Chapter $chapter
|
||||
* @param Page $page
|
||||
* @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->role = $role;
|
||||
$this->book = $book;
|
||||
$this->chapter = $chapter;
|
||||
$this->page = $page;
|
||||
// TODO - Update so admin still goes through filters
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,6 +308,10 @@ class PermissionService
|
||||
$explodedAction = explode('-', $action);
|
||||
$restrictionAction = end($explodedAction);
|
||||
|
||||
if ($role->system_name === 'admin') {
|
||||
return $this->createJointPermissionDataArray($entity, $role, $action, true, true);
|
||||
}
|
||||
|
||||
if ($entity->isA('book')) {
|
||||
|
||||
if (!$entity->restricted) {
|
||||
@ -461,6 +471,51 @@ class PermissionService
|
||||
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
|
||||
* @param $query
|
||||
@ -608,7 +663,7 @@ class PermissionService
|
||||
private function isAdmin()
|
||||
{
|
||||
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;
|
||||
|
@ -37,7 +37,7 @@ class ViewService
|
||||
|
||||
// Otherwise create new view count
|
||||
$entity->views()->save($this->view->create([
|
||||
'user_id' => user()->id,
|
||||
'user_id' => $user->id,
|
||||
'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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param bool $cache
|
||||
|
Loading…
Reference in New Issue
Block a user