Showing
7 changed files
with
92 additions
and
41 deletions
| ... | @@ -22,6 +22,7 @@ class BookController extends Controller | ... | @@ -22,6 +22,7 @@ class BookController extends Controller |
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | * BookController constructor. | 24 | * BookController constructor. |
| 25 | + * @param EntityRepo $entityRepo | ||
| 25 | * @param BookRepo $bookRepo | 26 | * @param BookRepo $bookRepo |
| 26 | * @param PageRepo $pageRepo | 27 | * @param PageRepo $pageRepo |
| 27 | * @param ChapterRepo $chapterRepo | 28 | * @param ChapterRepo $chapterRepo | ... | ... |
| ... | @@ -93,47 +93,32 @@ class BookRepo extends EntityRepo | ... | @@ -93,47 +93,32 @@ class BookRepo extends EntityRepo |
| 93 | */ | 93 | */ |
| 94 | public function getChildren(Book $book, $filterDrafts = false) | 94 | public function getChildren(Book $book, $filterDrafts = false) |
| 95 | { | 95 | { |
| 96 | - $pageQuery = $book->pages()->where('chapter_id', '=', 0); | 96 | + $q = $this->permissionService->bookChildrenQuery($book->id, $filterDrafts); |
| 97 | - $pageQuery = $this->permissionService->enforcePageRestrictions($pageQuery, 'view'); | 97 | + $entities = []; |
| 98 | + $parents = []; | ||
| 99 | + $tree = []; | ||
| 98 | 100 | ||
| 99 | - if ($filterDrafts) { | 101 | + foreach ($q as $index => $rawEntity) { |
| 100 | - $pageQuery = $pageQuery->where('draft', '=', false); | 102 | + if ($rawEntity->entity_type === 'Bookstack\\Page') { |
| 103 | + $entities[$index] = $this->page->newFromBuilder($rawEntity); | ||
| 104 | + } else if ($rawEntity->entity_type === 'Bookstack\\Chapter') { | ||
| 105 | + $entities[$index] = $this->chapter->newFromBuilder($rawEntity); | ||
| 106 | + $key = $entities[$index]->entity_type . ':' . $entities[$index]->id; | ||
| 107 | + $parents[$key] = $entities[$index]; | ||
| 108 | + $parents[$key]->setAttribute('pages', collect()); | ||
| 109 | + } | ||
| 110 | + if ($entities[$index]->chapter_id === 0) $tree[] = $entities[$index]; | ||
| 111 | + $entities[$index]->book = $book; | ||
| 101 | } | 112 | } |
| 102 | 113 | ||
| 103 | - $pages = $pageQuery->get(); | 114 | + foreach ($entities as $entity) { |
| 104 | - | 115 | + if ($entity->chapter_id === 0) continue; |
| 105 | - $chapterQuery = $book->chapters()->with(['pages' => function ($query) use ($filterDrafts) { | 116 | + $parentKey = 'Bookstack\\Chapter:' . $entity->chapter_id; |
| 106 | - $this->permissionService->enforcePageRestrictions($query, 'view'); | 117 | + $chapter = $parents[$parentKey]; |
| 107 | - if ($filterDrafts) $query->where('draft', '=', false); | 118 | + $chapter->pages->push($entity); |
| 108 | - }]); | ||
| 109 | - $chapterQuery = $this->permissionService->enforceChapterRestrictions($chapterQuery, 'view'); | ||
| 110 | - $chapters = $chapterQuery->get(); | ||
| 111 | - $children = $pages->values(); | ||
| 112 | - foreach ($chapters as $chapter) { | ||
| 113 | - $children->push($chapter); | ||
| 114 | } | 119 | } |
| 115 | - $bookSlug = $book->slug; | ||
| 116 | - | ||
| 117 | - $children->each(function ($child) use ($bookSlug) { | ||
| 118 | - $child->setAttribute('bookSlug', $bookSlug); | ||
| 119 | - if ($child->isA('chapter')) { | ||
| 120 | - $child->pages->each(function ($page) use ($bookSlug) { | ||
| 121 | - $page->setAttribute('bookSlug', $bookSlug); | ||
| 122 | - }); | ||
| 123 | - $child->pages = $child->pages->sortBy(function ($child, $key) { | ||
| 124 | - $score = $child->priority; | ||
| 125 | - if ($child->draft) $score -= 100; | ||
| 126 | - return $score; | ||
| 127 | - }); | ||
| 128 | - } | ||
| 129 | - }); | ||
| 130 | 120 | ||
| 131 | - // Sort items with drafts first then by priority. | 121 | + return collect($tree); |
| 132 | - return $children->sortBy(function ($child, $key) { | ||
| 133 | - $score = $child->priority; | ||
| 134 | - if ($child->isA('page') && $child->draft) $score -= 100; | ||
| 135 | - return $score; | ||
| 136 | - }); | ||
| 137 | } | 122 | } |
| 138 | 123 | ||
| 139 | } | 124 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -7,7 +7,6 @@ use BookStack\Exceptions\NotFoundException; | ... | @@ -7,7 +7,6 @@ use BookStack\Exceptions\NotFoundException; |
| 7 | use BookStack\Page; | 7 | use BookStack\Page; |
| 8 | use BookStack\Services\PermissionService; | 8 | use BookStack\Services\PermissionService; |
| 9 | use BookStack\Services\ViewService; | 9 | use BookStack\Services\ViewService; |
| 10 | -use Illuminate\Database\Eloquent\Builder; | ||
| 11 | use Illuminate\Support\Collection; | 10 | use Illuminate\Support\Collection; |
| 12 | 11 | ||
| 13 | class EntityRepo | 12 | class EntityRepo |
| ... | @@ -127,6 +126,7 @@ class EntityRepo | ... | @@ -127,6 +126,7 @@ class EntityRepo |
| 127 | public function getBySlug($type, $slug, $bookSlug = false) | 126 | public function getBySlug($type, $slug, $bookSlug = false) |
| 128 | { | 127 | { |
| 129 | $q = $this->entityQuery($type)->where('slug', '=', $slug); | 128 | $q = $this->entityQuery($type)->where('slug', '=', $slug); |
| 129 | + | ||
| 130 | if (strtolower($type) === 'chapter' || strtolower($type) === 'page') { | 130 | if (strtolower($type) === 'chapter' || strtolower($type) === 'page') { |
| 131 | $q = $q->where('book_id', '=', function($query) use ($bookSlug) { | 131 | $q = $q->where('book_id', '=', function($query) use ($bookSlug) { |
| 132 | $query->select('id') | 132 | $query->select('id') | ... | ... |
| ... | @@ -114,7 +114,7 @@ class ActivityService | ... | @@ -114,7 +114,7 @@ class ActivityService |
| 114 | 114 | ||
| 115 | $activity = $this->permissionService | 115 | $activity = $this->permissionService |
| 116 | ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type') | 116 | ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type') |
| 117 | - ->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get(); | 117 | + ->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * $page)->take($count)->get(); |
| 118 | 118 | ||
| 119 | return $this->filterSimilar($activity); | 119 | return $this->filterSimilar($activity); |
| 120 | } | 120 | } | ... | ... |
| ... | @@ -8,6 +8,7 @@ use BookStack\Ownable; | ... | @@ -8,6 +8,7 @@ use BookStack\Ownable; |
| 8 | use BookStack\Page; | 8 | use BookStack\Page; |
| 9 | use BookStack\Role; | 9 | use BookStack\Role; |
| 10 | use BookStack\User; | 10 | use BookStack\User; |
| 11 | +use Illuminate\Database\Connection; | ||
| 11 | use Illuminate\Database\Eloquent\Builder; | 12 | use Illuminate\Database\Eloquent\Builder; |
| 12 | use Illuminate\Support\Collection; | 13 | use Illuminate\Support\Collection; |
| 13 | 14 | ||
| ... | @@ -23,6 +24,8 @@ class PermissionService | ... | @@ -23,6 +24,8 @@ class PermissionService |
| 23 | public $chapter; | 24 | public $chapter; |
| 24 | public $page; | 25 | public $page; |
| 25 | 26 | ||
| 27 | + protected $db; | ||
| 28 | + | ||
| 26 | protected $jointPermission; | 29 | protected $jointPermission; |
| 27 | protected $role; | 30 | protected $role; |
| 28 | 31 | ||
| ... | @@ -31,18 +34,21 @@ class PermissionService | ... | @@ -31,18 +34,21 @@ class PermissionService |
| 31 | /** | 34 | /** |
| 32 | * PermissionService constructor. | 35 | * PermissionService constructor. |
| 33 | * @param JointPermission $jointPermission | 36 | * @param JointPermission $jointPermission |
| 37 | + * @param Connection $db | ||
| 34 | * @param Book $book | 38 | * @param Book $book |
| 35 | * @param Chapter $chapter | 39 | * @param Chapter $chapter |
| 36 | * @param Page $page | 40 | * @param Page $page |
| 37 | * @param Role $role | 41 | * @param Role $role |
| 38 | */ | 42 | */ |
| 39 | - public function __construct(JointPermission $jointPermission, Book $book, Chapter $chapter, Page $page, Role $role) | 43 | + public function __construct(JointPermission $jointPermission, Connection $db, Book $book, Chapter $chapter, Page $page, Role $role) |
| 40 | { | 44 | { |
| 45 | + $this->db = $db; | ||
| 41 | $this->jointPermission = $jointPermission; | 46 | $this->jointPermission = $jointPermission; |
| 42 | $this->role = $role; | 47 | $this->role = $role; |
| 43 | $this->book = $book; | 48 | $this->book = $book; |
| 44 | $this->chapter = $chapter; | 49 | $this->chapter = $chapter; |
| 45 | $this->page = $page; | 50 | $this->page = $page; |
| 51 | + // TODO - Update so admin still goes through filters | ||
| 46 | } | 52 | } |
| 47 | 53 | ||
| 48 | /** | 54 | /** |
| ... | @@ -302,6 +308,10 @@ class PermissionService | ... | @@ -302,6 +308,10 @@ class PermissionService |
| 302 | $explodedAction = explode('-', $action); | 308 | $explodedAction = explode('-', $action); |
| 303 | $restrictionAction = end($explodedAction); | 309 | $restrictionAction = end($explodedAction); |
| 304 | 310 | ||
| 311 | + if ($role->system_name === 'admin') { | ||
| 312 | + return $this->createJointPermissionDataArray($entity, $role, $action, true, true); | ||
| 313 | + } | ||
| 314 | + | ||
| 305 | if ($entity->isA('book')) { | 315 | if ($entity->isA('book')) { |
| 306 | 316 | ||
| 307 | if (!$entity->restricted) { | 317 | if (!$entity->restricted) { |
| ... | @@ -461,6 +471,51 @@ class PermissionService | ... | @@ -461,6 +471,51 @@ class PermissionService |
| 461 | return $q; | 471 | return $q; |
| 462 | } | 472 | } |
| 463 | 473 | ||
| 474 | + public function bookChildrenQuery($book_id, $filterDrafts = false) { | ||
| 475 | + | ||
| 476 | + // Draft setup | ||
| 477 | + $params = [ | ||
| 478 | + 'userId' => $this->currentUser()->id, | ||
| 479 | + 'bookIdPage' => $book_id, | ||
| 480 | + 'bookIdChapter' => $book_id | ||
| 481 | + ]; | ||
| 482 | + if (!$filterDrafts) { | ||
| 483 | + $params['userIdDrafts'] = $this->currentUser()->id; | ||
| 484 | + } | ||
| 485 | + // Role setup | ||
| 486 | + $userRoles = $this->getRoles(); | ||
| 487 | + $roleBindings = []; | ||
| 488 | + $roleValues = []; | ||
| 489 | + foreach ($userRoles as $index => $roleId) { | ||
| 490 | + $roleBindings[':role'.$index] = $roleId; | ||
| 491 | + $roleValues['role'.$index] = $roleId; | ||
| 492 | + } | ||
| 493 | + // TODO - Clean this up, Maybe extract into a nice class for doing these kind of manual things | ||
| 494 | + // Something which will handle the above role crap in a nice clean way | ||
| 495 | + $roleBindingString = implode(',', array_keys($roleBindings)); | ||
| 496 | + $query = "SELECT * from ( | ||
| 497 | +(SELECT 'Bookstack\\\Page' as entity_type, id, slug, name, text, '' as description, book_id, priority, chapter_id, draft FROM {$this->page->getTable()} | ||
| 498 | + where book_id = :bookIdPage AND ". ($filterDrafts ? '(draft = 0)' : '(draft = 0 OR (draft = 1 AND created_by = :userIdDrafts))') .") | ||
| 499 | +UNION | ||
| 500 | +(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) | ||
| 501 | +) as U WHERE ( | ||
| 502 | + SELECT COUNT(*) FROM {$this->jointPermission->getTable()} jp | ||
| 503 | + WHERE | ||
| 504 | + jp.entity_id=U.id AND | ||
| 505 | + jp.entity_type=U.entity_type AND | ||
| 506 | + jp.action = 'view' AND | ||
| 507 | + jp.role_id IN ({$roleBindingString}) AND | ||
| 508 | + ( | ||
| 509 | + jp.has_permission = 1 OR | ||
| 510 | + (jp.has_permission_own = 1 AND jp.created_by = :userId) | ||
| 511 | + ) | ||
| 512 | +) > 0 | ||
| 513 | +ORDER BY draft desc, priority asc"; | ||
| 514 | + | ||
| 515 | + $this->clean(); | ||
| 516 | + return $this->db->select($query, array_replace($roleValues, $params)); | ||
| 517 | + } | ||
| 518 | + | ||
| 464 | /** | 519 | /** |
| 465 | * Add restrictions for a page query | 520 | * Add restrictions for a page query |
| 466 | * @param $query | 521 | * @param $query |
| ... | @@ -608,7 +663,7 @@ class PermissionService | ... | @@ -608,7 +663,7 @@ class PermissionService |
| 608 | private function isAdmin() | 663 | private function isAdmin() |
| 609 | { | 664 | { |
| 610 | if ($this->isAdminUser === null) { | 665 | if ($this->isAdminUser === null) { |
| 611 | - $this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasRole('admin') : false; | 666 | + $this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasSystemRole('admin') : false; |
| 612 | } | 667 | } |
| 613 | 668 | ||
| 614 | return $this->isAdminUser; | 669 | return $this->isAdminUser; | ... | ... |
| ... | @@ -37,7 +37,7 @@ class ViewService | ... | @@ -37,7 +37,7 @@ class ViewService |
| 37 | 37 | ||
| 38 | // Otherwise create new view count | 38 | // Otherwise create new view count |
| 39 | $entity->views()->save($this->view->create([ | 39 | $entity->views()->save($this->view->create([ |
| 40 | - 'user_id' => user()->id, | 40 | + 'user_id' => $user->id, |
| 41 | 'views' => 1 | 41 | 'views' => 1 |
| 42 | ])); | 42 | ])); |
| 43 | 43 | ... | ... |
| ... | @@ -75,6 +75,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon | ... | @@ -75,6 +75,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /** | 77 | /** |
| 78 | + * Check if the user has a role. | ||
| 79 | + * @param $role | ||
| 80 | + * @return mixed | ||
| 81 | + */ | ||
| 82 | + public function hasSystemRole($role) | ||
| 83 | + { | ||
| 84 | + return $this->roles->pluck('system_name')->contains('admin'); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 78 | * Get all permissions belonging to a the current user. | 88 | * Get all permissions belonging to a the current user. |
| 79 | * @param bool $cache | 89 | * @param bool $cache |
| 80 | * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough | 90 | * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough | ... | ... |
-
Please register or sign in to post a comment