/**
* BookController constructor.
+ * @param EntityRepo $entityRepo
* @param BookRepo $bookRepo
* @param PageRepo $pageRepo
* @param ChapterRepo $chapterRepo
*/
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);
+ 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;
}
- $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);
+ foreach ($entities as $entity) {
+ if ($entity->chapter_id === 0) continue;
+ $parentKey = 'Bookstack\\Chapter:' . $entity->chapter_id;
+ $chapter = $parents[$parentKey];
+ $chapter->pages->push($entity);
}
- $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;
- });
- }
- });
- // 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;
- });
+ return collect($tree);
}
}
\ No newline at end of file
use BookStack\Page;
use BookStack\Services\PermissionService;
use BookStack\Services\ViewService;
-use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
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')
$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);
}
use BookStack\Page;
use BookStack\Role;
use BookStack\User;
+use Illuminate\Database\Connection;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
public $chapter;
public $page;
+ protected $db;
+
protected $jointPermission;
protected $role;
/**
* 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
}
/**
$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) {
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
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;
// Otherwise create new view count
$entity->views()->save($this->view->create([
- 'user_id' => user()->id,
+ 'user_id' => $user->id,
'views' => 1
]));
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