]> BookStack Code Mirror - bookstack/commitdiff
Rewrote book children query
authorDan Brown <redacted>
Sun, 1 Jan 2017 21:21:11 +0000 (21:21 +0000)
committerDan Brown <redacted>
Sun, 1 Jan 2017 21:21:11 +0000 (21:21 +0000)
app/Http/Controllers/BookController.php
app/Repos/BookRepo.php
app/Repos/EntityRepo.php
app/Services/ActivityService.php
app/Services/PermissionService.php
app/Services/ViewService.php
app/User.php

index 0b4749a48fa73958b7c653ee0972cdc195a1a7c7..b6856f273603726335e0ee7800b8408ff3c88469 100644 (file)
@@ -22,6 +22,7 @@ class BookController extends Controller
 
     /**
      * BookController constructor.
+     * @param EntityRepo $entityRepo
      * @param BookRepo $bookRepo
      * @param PageRepo $pageRepo
      * @param ChapterRepo $chapterRepo
index 3043d2916576398028f20e6dff1ce3519e534acd..f5d19bc3731f60fe5f5ec179169a35f1066c642a 100644 (file)
@@ -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);
+        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
index 40fdea54ee9be1bf636a4a728a517ec44cc1cf4d..dd3016c6c75262d27d504f5d0e06d78cbba68db1 100644 (file)
@@ -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')
index e4103623835af2d9c3c170a1a66e962cafb9743e..2368ba10aebd73a936ad39684be86d2a8e65241c 100644 (file)
@@ -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);
     }
index d5044c1bbdde580d3a65c3ae0e6d0b2f9dc27b0d..0db2d1b5e94d7f16fd7973c765331bcf3c925fc7 100644 (file)
@@ -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;
index 73b353d8f0a989cb40f93b9269e5dcdbb1d0b8bf..3285745ce4d8c5a3b1a9acc4adfa58ac77b50e29 100644 (file)
@@ -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
         ]));
 
index 09b189cbb55e084419309c3b6f154e77ed28d4ee..b5bb221e8652a29a2e8dbb19d84ac40799498bd8 100644 (file)
@@ -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
Morty Proxy This is a proxified and sanitized view of the page, visit original site.