From 3083979855c6395fd7a35fb92790e0efb37b44f6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 15 Jan 2023 17:38:08 +0000 Subject: [PATCH] Added method for using enity ownership in relation queries It has a large linear-entity-scaling performance impact though. --- app/Auth/Permissions/PermissionApplicator.php | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/app/Auth/Permissions/PermissionApplicator.php b/app/Auth/Permissions/PermissionApplicator.php index af6ca4d67..844fe4604 100644 --- a/app/Auth/Permissions/PermissionApplicator.php +++ b/app/Auth/Permissions/PermissionApplicator.php @@ -13,6 +13,7 @@ use BookStack\Traits\HasOwner; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\JoinClause; +use Illuminate\Support\Facades\DB; use InvalidArgumentException; class PermissionApplicator @@ -201,7 +202,7 @@ class PermissionApplicator $abilities['all'] = array_filter($abilities['all']); $abilities['own'] = array_filter($abilities['own']); - $query->where(function (Builder $query) use ($abilities, $fullEntityTypeColumn) { + $query->where(function (Builder $query) use ($abilities, $fullEntityTypeColumn, $entityTypeColumn) { $query->where('perms_user', '=', 1) ->orWhere(function (Builder $query) { $query->whereNull('perms_user')->where('perms_role', '=', 1); @@ -211,19 +212,19 @@ class PermissionApplicator }); if (count($abilities['all']) > 0) { - $query->orWhere(function (Builder $query) use ($abilities, $fullEntityTypeColumn) { + $query->orWhere(function (Builder $query) use ($abilities, $fullEntityTypeColumn, $entityTypeColumn) { $query->whereNull(['perms_user', 'perms_role', 'perms_fallback']); - if ($fullEntityTypeColumn) { + if ($entityTypeColumn) { $query->whereIn($fullEntityTypeColumn, array_keys($abilities['all'])); } }); } if (count($abilities['own']) > 0) { - $query->orWhere(function (Builder $query) use ($abilities, $fullEntityTypeColumn) { + $query->orWhere(function (Builder $query) use ($abilities, $fullEntityTypeColumn, $entityTypeColumn) { $query->whereNull(['perms_user', 'perms_role', 'perms_fallback']) ->where('owned_by', '=', $this->currentUser()->id); - if ($fullEntityTypeColumn) { + if ($entityTypeColumn) { $query->whereIn($fullEntityTypeColumn, array_keys($abilities['all'])); } }); @@ -317,6 +318,19 @@ class PermissionApplicator */ public function restrictEntityRelationQuery($query, string $tableName, string $entityIdColumn, string $entityTypeColumn) { + $query->leftJoinSub(function (QueryBuilder $query) { + $query->select(['id as entity_id', DB::raw("'page' as entity_type"), 'owned_by', 'deleted_at', 'draft'])->from('pages'); + $tablesByType = ['page' => 'pages', 'book' => 'books', 'chapter' => 'chapters', 'bookshelf' => 'bookshelves']; + foreach ($tablesByType as $type => $table) { + $query->unionAll(function (QueryBuilder $query) use ($type, $table) { + $query->select(['id as entity_id', DB::raw("'{$type}' as entity_type"), 'owned_by', 'deleted_at', DB::raw('0 as draft')])->from($table); + }); + } + }, 'entities', function (JoinClause $join) use ($tableName, $entityIdColumn, $entityTypeColumn) { + $join->on($tableName . '.' . $entityIdColumn, '=', 'entities.entity_id') + ->on($tableName . '.' . $entityTypeColumn, '=', 'entities.entity_type'); + }); + $this->applyPermissionsToQuery($query, $tableName, '', $entityIdColumn, $entityTypeColumn); // TODO - Test page draft access (Might allow drafts which should not be seen) @@ -335,6 +349,7 @@ class PermissionApplicator $this->applyPermissionsToQuery($query, $tableName, $morphClass, $pageIdColumn, ''); // TODO - Draft display + // TODO - Likely need owned_by entity join workaround as used above return $query; }