use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Facades\DB;
+/**
+ * Joint permissions provide a pre-query "cached" table of view permissions for all core entity
+ * types for all roles in the system. This class generates out that table for different scenarios.
+ */
class JointPermissionBuilder
{
/**
{
$roles = [$role];
$role->jointPermissions()->delete();
+ $role->load('permissions');
// Chunk through all books
$this->bookFetchQuery()->chunk(20, function ($books) use ($roles) {
// Create a mapping of explicit entity permissions
$permissionMap = [];
foreach ($permissions as $permission) {
- $key = $permission->restrictable_type . ':' . $permission->restrictable_id . ':' . $permission->role_id . ':' . $permission->action;
+ $key = $permission->restrictable_type . ':' . $permission->restrictable_id . ':' . $permission->role_id;
$isRestricted = $entityRestrictedMap[$permission->restrictable_type . ':' . $permission->restrictable_id];
$permissionMap[$key] = $isRestricted;
}
// Create Joint Permission Data
foreach ($entities as $entity) {
foreach ($roles as $role) {
- foreach ($this->getActions($entity) as $action) {
- $jointPermissions[] = $this->createJointPermissionData(
- $entity,
- $role->getRawAttribute('id'),
- $action,
- $permissionMap,
- $rolePermissionMap,
- $role->system_name === 'admin'
- );
- }
+ $jointPermissions[] = $this->createJointPermissionData(
+ $entity,
+ $role->getRawAttribute('id'),
+ $permissionMap,
+ $rolePermissionMap,
+ $role->system_name === 'admin'
+ );
}
}
protected function getEntityPermissionsForEntities(array $entities): array
{
$idsByType = $this->entitiesToTypeIdMap($entities);
- $permissionFetch = EntityPermission::query();
-
- foreach ($idsByType as $type => $ids) {
- $permissionFetch->orWhere(function (Builder $query) use ($type, $ids) {
- $query->where('restrictable_type', '=', $type)->whereIn('restrictable_id', $ids);
+ $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);
+ });
+ }
});
- }
return $permissionFetch->get()->all();
}
- /**
- * Get the actions related to an entity.
- */
- protected function getActions(SimpleEntityData $entity): array
- {
- $baseActions = ['view', 'update', 'delete'];
-
- if ($entity->type === 'chapter' || $entity->type === 'book') {
- $baseActions[] = 'page-create';
- }
-
- if ($entity->type === 'book') {
- $baseActions[] = 'chapter-create';
- }
-
- return $baseActions;
- }
-
/**
* Create entity permission data for an entity and role
* for a particular action.
*/
- protected function createJointPermissionData(SimpleEntityData $entity, int $roleId, string $action, array $permissionMap, array $rolePermissionMap, bool $isAdminRole): array
+ protected function createJointPermissionData(SimpleEntityData $entity, int $roleId, array $permissionMap, array $rolePermissionMap, bool $isAdminRole): array
{
- $permissionPrefix = (strpos($action, '-') === false ? ($entity->type . '-') : '') . $action;
+ $permissionPrefix = $entity->type . '-view';
$roleHasPermission = isset($rolePermissionMap[$roleId . ':' . $permissionPrefix . '-all']);
$roleHasPermissionOwn = isset($rolePermissionMap[$roleId . ':' . $permissionPrefix . '-own']);
- $explodedAction = explode('-', $action);
- $restrictionAction = end($explodedAction);
if ($isAdminRole) {
- return $this->createJointPermissionDataArray($entity, $roleId, $action, true, true);
+ return $this->createJointPermissionDataArray($entity, $roleId, true, true);
}
if ($entity->restricted) {
- $hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $roleId, $restrictionAction);
+ $hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $roleId);
- return $this->createJointPermissionDataArray($entity, $roleId, $action, $hasAccess, $hasAccess);
+ return $this->createJointPermissionDataArray($entity, $roleId, $hasAccess, $hasAccess);
}
if ($entity->type === 'book' || $entity->type === 'bookshelf') {
- return $this->createJointPermissionDataArray($entity, $roleId, $action, $roleHasPermission, $roleHasPermissionOwn);
+ return $this->createJointPermissionDataArray($entity, $roleId, $roleHasPermission, $roleHasPermissionOwn);
}
// 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, $restrictionAction);
+ $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $book, $roleId);
$hasPermissiveAccessToParents = !$book->restricted;
// For pages with a chapter, Check if explicit permissions are set on the Chapter
$chapter = $this->getChapter($entity->chapter_id);
$hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapter->restricted;
if ($chapter->restricted) {
- $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $chapter, $roleId, $restrictionAction);
+ $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $chapter, $roleId);
}
}
return $this->createJointPermissionDataArray(
$entity,
$roleId,
- $action,
($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)),
($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents))
);
/**
* Check for an active restriction in an entity map.
*/
- protected function mapHasActiveRestriction(array $entityMap, SimpleEntityData $entity, int $roleId, string $action): bool
+ protected function mapHasActiveRestriction(array $entityMap, SimpleEntityData $entity, int $roleId): bool
{
- $key = $entity->type . ':' . $entity->id . ':' . $roleId . ':' . $action;
+ $key = $entity->type . ':' . $entity->id . ':' . $roleId;
return $entityMap[$key] ?? false;
}
* Create an array of data with the information of an entity jointPermissions.
* Used to build data for bulk insertion.
*/
- protected function createJointPermissionDataArray(SimpleEntityData $entity, int $roleId, string $action, bool $permissionAll, bool $permissionOwn): array
+ protected function createJointPermissionDataArray(SimpleEntityData $entity, int $roleId, bool $permissionAll, bool $permissionOwn): array
{
return [
- 'action' => $action,
'entity_id' => $entity->id,
'entity_type' => $entity->type,
'has_permission' => $permissionAll,
return $query->where(function (Builder $parentQuery) {
$parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) {
$permissionQuery->whereIn('role_id', $this->getCurrentUserRoleIds())
- // TODO - Delete line once only views
- ->where('action', '=', 'view')
->where(function (Builder $query) {
$this->addJointHasPermissionCheck($query, $this->currentUser()->id);
});
$permissionQuery->select(['role_id'])->from('joint_permissions')
->whereColumn('joint_permissions.entity_id', '=', $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
->whereColumn('joint_permissions.entity_type', '=', $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'])
- ->where('joint_permissions.action', '=', 'view')
->whereIn('joint_permissions.role_id', $this->getCurrentUserRoleIds())
->where(function (QueryBuilder $query) {
$this->addJointHasPermissionCheck($query, $this->currentUser()->id);
$permissionQuery->select('joint_permissions.role_id')->from('joint_permissions')
->whereColumn('joint_permissions.entity_id', '=', $fullPageIdColumn)
->where('joint_permissions.entity_type', '=', $morphClass)
- ->where('joint_permissions.action', '=', 'view')
->whereIn('joint_permissions.role_id', $this->getCurrentUserRoleIds())
->where(function (QueryBuilder $query) {
$this->addJointHasPermissionCheck($query, $this->currentUser()->id);