]> BookStack Code Mirror - bookstack/blobdiff - app/Auth/Permissions/JointPermissionBuilder.php
Guest create page: name field autofocus
[bookstack] / app / Auth / Permissions / JointPermissionBuilder.php
index f377eef5ce55057fae0278bb0a9b6febb79511d5..114cff6191a35edc6e20494bd3305664c8a6eddd 100644 (file)
@@ -22,7 +22,7 @@ class JointPermissionBuilder
     /**
      * @var array<string, array<int, SimpleEntityData>>
      */
-    protected $entityCache;
+    protected array $entityCache;
 
     /**
      * Re-generate all entity permission from scratch.
@@ -40,7 +40,7 @@ class JointPermissionBuilder
         });
 
         // Chunk through all bookshelves
-        Bookshelf::query()->withTrashed()->select(['id', 'restricted', 'owned_by'])
+        Bookshelf::query()->withTrashed()->select(['id', 'owned_by'])
             ->chunk(50, function (EloquentCollection $shelves) use ($roles) {
                 $this->createManyJointPermissions($shelves->all(), $roles);
             });
@@ -92,7 +92,7 @@ class JointPermissionBuilder
         });
 
         // Chunk through all bookshelves
-        Bookshelf::query()->select(['id', 'restricted', 'owned_by'])
+        Bookshelf::query()->select(['id', 'owned_by'])
             ->chunk(50, function ($shelves) use ($roles) {
                 $this->createManyJointPermissions($shelves->all(), $roles);
             });
@@ -138,12 +138,12 @@ class JointPermissionBuilder
     protected function bookFetchQuery(): Builder
     {
         return Book::query()->withTrashed()
-            ->select(['id', 'restricted', 'owned_by'])->with([
+            ->select(['id', 'owned_by'])->with([
                 'chapters' => function ($query) {
-                    $query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id']);
+                    $query->withTrashed()->select(['id', 'owned_by', 'book_id']);
                 },
                 'pages' => function ($query) {
-                    $query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id', 'chapter_id']);
+                    $query->withTrashed()->select(['id', 'owned_by', 'book_id', 'chapter_id']);
                 },
             ]);
     }
@@ -218,7 +218,6 @@ class JointPermissionBuilder
             $simple = new SimpleEntityData();
             $simple->id = $attrs['id'];
             $simple->type = $entity->getMorphClass();
-            $simple->restricted = boolval($attrs['restricted'] ?? 0);
             $simple->owned_by = $attrs['owned_by'] ?? 0;
             $simple->book_id = $attrs['book_id'] ?? null;
             $simple->chapter_id = $attrs['chapter_id'] ?? null;
@@ -231,7 +230,7 @@ class JointPermissionBuilder
     /**
      * Create & Save entity jointPermissions for many entities and roles.
      *
-     * @param Entity[] $entities
+     * @param Entity[] $originalEntities
      * @param Role[]   $roles
      */
     protected function createManyJointPermissions(array $originalEntities, array $roles)
@@ -240,21 +239,14 @@ class JointPermissionBuilder
         $this->readyEntityCache($entities);
         $jointPermissions = [];
 
-        // Create a mapping of entity restricted statuses
-        $entityRestrictedMap = [];
-        foreach ($entities as $entity) {
-            $entityRestrictedMap[$entity->type . ':' . $entity->id] = $entity->restricted;
-        }
-
         // Fetch related entity permissions
         $permissions = $this->getEntityPermissionsForEntities($entities);
 
         // Create a mapping of explicit entity permissions
         $permissionMap = [];
         foreach ($permissions as $permission) {
-            $key = $permission->restrictable_type . ':' . $permission->restrictable_id . ':' . $permission->role_id;
-            $isRestricted = $entityRestrictedMap[$permission->restrictable_type . ':' . $permission->restrictable_id];
-            $permissionMap[$key] = $isRestricted;
+            $key = $permission->entity_type . ':' . $permission->entity_id . ':' . $permission->role_id;
+            $permissionMap[$key] = $permission->view;
         }
 
         // Create a mapping of role permissions
@@ -319,11 +311,10 @@ class JointPermissionBuilder
     {
         $idsByType = $this->entitiesToTypeIdMap($entities);
         $permissionFetch = EntityPermission::query()
-            ->where('action', '=', 'view')
             ->where(function (Builder $query) use ($idsByType) {
                 foreach ($idsByType as $type => $ids) {
                     $query->orWhere(function (Builder $query) use ($type, $ids) {
-                        $query->where('restrictable_type', '=', $type)->whereIn('restrictable_id', $ids);
+                        $query->where('entity_type', '=', $type)->whereIn('entity_id', $ids);
                     });
                 }
             });
@@ -345,7 +336,7 @@ class JointPermissionBuilder
             return $this->createJointPermissionDataArray($entity, $roleId, true, true);
         }
 
-        if ($entity->restricted) {
+        if ($this->entityPermissionsActiveForRole($permissionMap, $entity, $roleId)) {
             $hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $roleId);
 
             return $this->createJointPermissionDataArray($entity, $roleId, $hasAccess, $hasAccess);
@@ -358,13 +349,14 @@ class JointPermissionBuilder
         // For chapters and pages, Check if explicit permissions are set on the Book.
         $book = $this->getBook($entity->book_id);
         $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $book, $roleId);
-        $hasPermissiveAccessToParents = !$book->restricted;
+        $hasPermissiveAccessToParents = !$this->entityPermissionsActiveForRole($permissionMap, $book, $roleId);
 
         // For pages with a chapter, Check if explicit permissions are set on the Chapter
         if ($entity->type === 'page' && $entity->chapter_id !== 0) {
             $chapter = $this->getChapter($entity->chapter_id);
-            $hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapter->restricted;
-            if ($chapter->restricted) {
+            $chapterRestricted = $this->entityPermissionsActiveForRole($permissionMap, $chapter, $roleId);
+            $hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapterRestricted;
+            if ($chapterRestricted) {
                 $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $chapter, $roleId);
             }
         }
@@ -377,14 +369,25 @@ class JointPermissionBuilder
         );
     }
 
+    /**
+     * Check if entity permissions are defined within the given map, for the given entity and role.
+     * Checks for the default `role_id=0` backup option as a fallback.
+     */
+    protected function entityPermissionsActiveForRole(array $permissionMap, SimpleEntityData $entity, int $roleId): bool
+    {
+        $keyPrefix = $entity->type . ':' . $entity->id . ':';
+        return isset($permissionMap[$keyPrefix . $roleId]) || isset($permissionMap[$keyPrefix . '0']);
+    }
+
     /**
      * Check for an active restriction in an entity map.
      */
     protected function mapHasActiveRestriction(array $entityMap, SimpleEntityData $entity, int $roleId): bool
     {
-        $key = $entity->type . ':' . $entity->id . ':' . $roleId;
+        $roleKey = $entity->type . ':' . $entity->id . ':' . $roleId;
+        $defaultKey = $entity->type . ':' . $entity->id . ':0';
 
-        return $entityMap[$key] ?? false;
+        return $entityMap[$roleKey] ?? $entityMap[$defaultKey] ?? false;
     }
 
     /**