Created big scary query to apply permissions via new format

This commit is contained in:
Dan Brown 2022-12-22 20:32:06 +00:00
parent 39acbeac68
commit 7330139555
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
4 changed files with 72 additions and 14 deletions

View File

@ -2,7 +2,6 @@
namespace BookStack\Auth\Permissions;
use BookStack\Auth\Role;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\BookChild;
use BookStack\Entities\Models\Bookshelf;

View File

@ -183,20 +183,70 @@ class PermissionApplicator
* Limit the given entity query so that the query will only
* return items that the user has view permission for.
*/
public function restrictEntityQuery(Builder $query): Builder
public function restrictEntityQuery(Builder $query, string $morphClass): Builder
{
return $query->where(function (Builder $parentQuery) {
$parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) {
$permissionQuery->whereIn('role_id', $this->getCurrentUserRoleIds())
->where(function (Builder $query) {
$this->addJointHasPermissionCheck($query, $this->currentUser()->id);
});
})->orWhereHas('jointUserPermissions', function (Builder $query) {
$query->where('user_id', '=', $this->currentUser()->id)->where('has_permission', '=', true);
});
})->whereDoesntHave('jointUserPermissions', function (Builder $query) {
$query->where('user_id', '=', $this->currentUser()->id)->where('has_permission', '=', false);
$this->getCurrentUserRoleIds();
$this->currentUser()->id;
$userViewAll = userCan($morphClass . '-view-all');
$userViewOwn = userCan($morphClass . '-view-own');
// TODO - Leave this as the new admin workaround?
// Or auto generate collapsed role permissions for admins?
if (\user()->hasSystemRole('admin')) {
return $query;
}
// Fallback permission join
$query->joinSub(function (QueryBuilder $joinQuery) use ($morphClass) {
$joinQuery->select(['entity_id'])->selectRaw('max(view) as perms_fallback')
->from('entity_permissions_collapsed')
->where('entity_type', '=', $morphClass)
->whereNull(['role_id', 'user_id'])
->groupBy('entity_id');
}, 'p_f', 'id', '=', 'p_f.entity_id', 'left');
// Role permission join
$query->joinSub(function (QueryBuilder $joinQuery) use ($morphClass) {
$joinQuery->select(['entity_id'])->selectRaw('max(view) as perms_role')
->from('entity_permissions_collapsed')
->where('entity_type', '=', $morphClass)
->whereIn('role_id', $this->getCurrentUserRoleIds())
->groupBy('entity_id');
}, 'p_r', 'id', '=', 'p_r.entity_id', 'left');
// User permission join
$query->joinSub(function (QueryBuilder $joinQuery) use ($morphClass) {
$joinQuery->select(['entity_id'])->selectRaw('max(view) as perms_user')
->from('entity_permissions_collapsed')
->where('entity_type', '=', $morphClass)
->where('user_id', '=', $this->currentUser()->id)
->groupBy('entity_id');
}, 'p_u', 'id', '=', 'p_u.entity_id', 'left');
// Where permissions apply
$query->where(function (Builder $query) use ($userViewOwn, $userViewAll) {
$query->where('perms_user', '=', 1)
->orWhere(function (Builder $query) {
$query->whereNull('perms_user')->where('perms_role', '=', 1);
})->orWhere(function (Builder $query) {
$query->whereNull(['perms_user', 'perms_role'])
->where('perms_fallback', '=', 1);
});
if ($userViewAll) {
$query->orWhere(function (Builder $query) {
$query->whereNull(['perms_user', 'perms_role', 'perms_fallback']);
});
} else if ($userViewOwn) {
$query->orWhere(function (Builder $query) {
$query->whereNull(['perms_user', 'perms_role', 'perms_fallback'])
->where('created_by', '=', $this->currentUser()->id);
});
}
});
return $query;
}
/**
@ -226,6 +276,9 @@ class PermissionApplicator
$tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
$pageMorphClass = (new Page())->getMorphClass();
// TODO;
return $query;
$q = $query->where(function ($query) use ($tableDetails) {
$query->whereExists(function ($permissionQuery) use ($tableDetails) {
/** @var Builder $permissionQuery */
@ -275,6 +328,9 @@ class PermissionApplicator
$fullPageIdColumn = $tableName . '.' . $pageIdColumn;
$morphClass = (new Page())->getMorphClass();
// TODO
return $query;
$existsQuery = function ($permissionQuery) use ($fullPageIdColumn, $morphClass) {
/** @var Builder $permissionQuery */
$permissionQuery->select('joint_permissions.role_id')->from('joint_permissions')

View File

@ -70,7 +70,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
*/
public function scopeVisible(Builder $query): Builder
{
return app()->make(PermissionApplicator::class)->restrictEntityQuery($query);
return app()->make(PermissionApplicator::class)->restrictEntityQuery($query, $this->getMorphClass());
}
/**

View File

@ -8,8 +8,11 @@ Tests are categorised by the most specific element involved in the scenario, whe
- User entity permissions.
- Role entity permissions.
- Fallback entity permissions.
- Role permissions.
- TODO - Test fallback in the context of the above.
## General Permission Logical Rules
The below are some general rules we follow to standardise the behaviour of permissions in the platform: