Added method for using enity ownership in relation queries

It has a large linear-entity-scaling performance impact though.
This commit is contained in:
Dan Brown 2023-01-15 17:38:08 +00:00
parent 55642a33ee
commit 3083979855
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9

View File

@ -13,6 +13,7 @@ use BookStack\Traits\HasOwner;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException; use InvalidArgumentException;
class PermissionApplicator class PermissionApplicator
@ -201,7 +202,7 @@ class PermissionApplicator
$abilities['all'] = array_filter($abilities['all']); $abilities['all'] = array_filter($abilities['all']);
$abilities['own'] = array_filter($abilities['own']); $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) $query->where('perms_user', '=', 1)
->orWhere(function (Builder $query) { ->orWhere(function (Builder $query) {
$query->whereNull('perms_user')->where('perms_role', '=', 1); $query->whereNull('perms_user')->where('perms_role', '=', 1);
@ -211,19 +212,19 @@ class PermissionApplicator
}); });
if (count($abilities['all']) > 0) { 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']); $query->whereNull(['perms_user', 'perms_role', 'perms_fallback']);
if ($fullEntityTypeColumn) { if ($entityTypeColumn) {
$query->whereIn($fullEntityTypeColumn, array_keys($abilities['all'])); $query->whereIn($fullEntityTypeColumn, array_keys($abilities['all']));
} }
}); });
} }
if (count($abilities['own']) > 0) { 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']) $query->whereNull(['perms_user', 'perms_role', 'perms_fallback'])
->where('owned_by', '=', $this->currentUser()->id); ->where('owned_by', '=', $this->currentUser()->id);
if ($fullEntityTypeColumn) { if ($entityTypeColumn) {
$query->whereIn($fullEntityTypeColumn, array_keys($abilities['all'])); $query->whereIn($fullEntityTypeColumn, array_keys($abilities['all']));
} }
}); });
@ -317,6 +318,19 @@ class PermissionApplicator
*/ */
public function restrictEntityRelationQuery($query, string $tableName, string $entityIdColumn, string $entityTypeColumn) 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); $this->applyPermissionsToQuery($query, $tableName, '', $entityIdColumn, $entityTypeColumn);
// TODO - Test page draft access (Might allow drafts which should not be seen) // 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, ''); $this->applyPermissionsToQuery($query, $tableName, $morphClass, $pageIdColumn, '');
// TODO - Draft display // TODO - Draft display
// TODO - Likely need owned_by entity join workaround as used above
return $query; return $query;
} }