mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-31 15:24:31 +03:00
Started new permission-caching/querying model
This commit is contained in:
37
app/Auth/Permissions/EntityPermissionMap.php
Normal file
37
app/Auth/Permissions/EntityPermissionMap.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BookStack\Auth\Permissions;
|
||||||
|
|
||||||
|
class EntityPermissionMap
|
||||||
|
{
|
||||||
|
protected array $map = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param EntityPermission[] $permissions
|
||||||
|
*/
|
||||||
|
public function __construct(array $permissions = [])
|
||||||
|
{
|
||||||
|
foreach ($permissions as $entityPermission) {
|
||||||
|
$this->addPermission($entityPermission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addPermission(EntityPermission $permission)
|
||||||
|
{
|
||||||
|
$entityCombinedId = $permission->entity_type . ':' . $permission->entity_id;
|
||||||
|
|
||||||
|
if (!isset($this->map[$entityCombinedId])) {
|
||||||
|
$this->map[$entityCombinedId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->map[$entityCombinedId][] = $permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return EntityPermission[]
|
||||||
|
*/
|
||||||
|
public function getForEntity(string $typeIdString): array
|
||||||
|
{
|
||||||
|
return $this->map[$typeIdString] ?? [];
|
||||||
|
}
|
||||||
|
}
|
@ -19,31 +19,23 @@ use Illuminate\Support\Facades\DB;
|
|||||||
*/
|
*/
|
||||||
class JointPermissionBuilder
|
class JointPermissionBuilder
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var array<string, array<int, SimpleEntityData>>
|
|
||||||
*/
|
|
||||||
protected array $entityCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-generate all entity permission from scratch.
|
* Re-generate all entity permission from scratch.
|
||||||
*/
|
*/
|
||||||
public function rebuildForAll()
|
public function rebuildForAll()
|
||||||
{
|
{
|
||||||
JointPermission::query()->truncate();
|
DB::table('entity_permissions_collapsed')->truncate();
|
||||||
JointUserPermission::query()->truncate();
|
|
||||||
|
|
||||||
// Get all roles (Should be the most limited dimension)
|
|
||||||
$roles = Role::query()->with('permissions')->get()->all();
|
|
||||||
|
|
||||||
// Chunk through all books
|
// Chunk through all books
|
||||||
$this->bookFetchQuery()->chunk(5, function (EloquentCollection $books) use ($roles) {
|
$this->bookFetchQuery()->chunk(5, function (EloquentCollection $books) {
|
||||||
$this->buildJointPermissionsForBooks($books, $roles);
|
$this->buildJointPermissionsForBooks($books);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Chunk through all bookshelves
|
// Chunk through all bookshelves
|
||||||
Bookshelf::query()->withTrashed()->select(['id', 'owned_by'])
|
Bookshelf::query()->withTrashed()
|
||||||
->chunk(50, function (EloquentCollection $shelves) use ($roles) {
|
->select(['id', 'owned_by'])
|
||||||
$this->createManyJointPermissions($shelves->all(), $roles);
|
->chunk(50, function (EloquentCollection $shelves) {
|
||||||
|
$this->generateCollapsedPermissions($shelves->all());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +47,7 @@ class JointPermissionBuilder
|
|||||||
$entities = [$entity];
|
$entities = [$entity];
|
||||||
if ($entity instanceof Book) {
|
if ($entity instanceof Book) {
|
||||||
$books = $this->bookFetchQuery()->where('id', '=', $entity->id)->get();
|
$books = $this->bookFetchQuery()->where('id', '=', $entity->id)->get();
|
||||||
$this->buildJointPermissionsForBooks($books, Role::query()->with('permissions')->get()->all(), true);
|
$this->buildJointPermissionsForBooks($books, true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -78,61 +70,6 @@ class JointPermissionBuilder
|
|||||||
$this->buildJointPermissionsForEntities($entities);
|
$this->buildJointPermissionsForEntities($entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the entity jointPermissions for a particular role.
|
|
||||||
*/
|
|
||||||
public function rebuildForRole(Role $role)
|
|
||||||
{
|
|
||||||
$roles = [$role];
|
|
||||||
$role->jointPermissions()->delete();
|
|
||||||
$role->load('permissions');
|
|
||||||
|
|
||||||
// Chunk through all books
|
|
||||||
$this->bookFetchQuery()->chunk(20, function ($books) use ($roles) {
|
|
||||||
$this->buildJointPermissionsForBooks($books, $roles);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Chunk through all bookshelves
|
|
||||||
Bookshelf::query()->select(['id', 'owned_by'])
|
|
||||||
->chunk(50, function ($shelves) use ($roles) {
|
|
||||||
$this->createManyJointPermissions($shelves->all(), $roles);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the local entity cache and ensure it's empty.
|
|
||||||
*
|
|
||||||
* @param SimpleEntityData[] $entities
|
|
||||||
*/
|
|
||||||
protected function readyEntityCache(array $entities)
|
|
||||||
{
|
|
||||||
$this->entityCache = [];
|
|
||||||
|
|
||||||
foreach ($entities as $entity) {
|
|
||||||
if (!isset($this->entityCache[$entity->type])) {
|
|
||||||
$this->entityCache[$entity->type] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->entityCache[$entity->type][$entity->id] = $entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a book via ID, Checks local cache.
|
|
||||||
*/
|
|
||||||
protected function getBook(int $bookId): SimpleEntityData
|
|
||||||
{
|
|
||||||
return $this->entityCache['book'][$bookId];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a chapter via ID, Checks local cache.
|
|
||||||
*/
|
|
||||||
protected function getChapter(int $chapterId): SimpleEntityData
|
|
||||||
{
|
|
||||||
return $this->entityCache['chapter'][$chapterId];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a query for fetching a book with its children.
|
* Get a query for fetching a book with its children.
|
||||||
*/
|
*/
|
||||||
@ -152,7 +89,7 @@ class JointPermissionBuilder
|
|||||||
/**
|
/**
|
||||||
* Build joint permissions for the given book and role combinations.
|
* Build joint permissions for the given book and role combinations.
|
||||||
*/
|
*/
|
||||||
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false)
|
protected function buildJointPermissionsForBooks(EloquentCollection $books, bool $deleteOld = false)
|
||||||
{
|
{
|
||||||
$entities = clone $books;
|
$entities = clone $books;
|
||||||
|
|
||||||
@ -170,7 +107,7 @@ class JointPermissionBuilder
|
|||||||
$this->deleteManyJointPermissionsForEntities($entities->all());
|
$this->deleteManyJointPermissionsForEntities($entities->all());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->createManyJointPermissions($entities->all(), $roles);
|
$this->generateCollapsedPermissions($entities->all());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,9 +115,8 @@ class JointPermissionBuilder
|
|||||||
*/
|
*/
|
||||||
protected function buildJointPermissionsForEntities(array $entities)
|
protected function buildJointPermissionsForEntities(array $entities)
|
||||||
{
|
{
|
||||||
$roles = Role::query()->get()->values()->all();
|
|
||||||
$this->deleteManyJointPermissionsForEntities($entities);
|
$this->deleteManyJointPermissionsForEntities($entities);
|
||||||
$this->createManyJointPermissions($entities, $roles);
|
$this->generateCollapsedPermissions($entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,11 +132,7 @@ class JointPermissionBuilder
|
|||||||
DB::transaction(function () use ($idsByType) {
|
DB::transaction(function () use ($idsByType) {
|
||||||
foreach ($idsByType as $type => $ids) {
|
foreach ($idsByType as $type => $ids) {
|
||||||
foreach (array_chunk($ids, 1000) as $idChunk) {
|
foreach (array_chunk($ids, 1000) as $idChunk) {
|
||||||
DB::table('joint_permissions')
|
DB::table('entity_permissions_collapsed')
|
||||||
->where('entity_type', '=', $type)
|
|
||||||
->whereIn('entity_id', $idChunk)
|
|
||||||
->delete();
|
|
||||||
DB::table('joint_user_permissions')
|
|
||||||
->where('entity_type', '=', $type)
|
->where('entity_type', '=', $type)
|
||||||
->whereIn('entity_id', $idChunk)
|
->whereIn('entity_id', $idChunk)
|
||||||
->delete();
|
->delete();
|
||||||
@ -233,72 +165,69 @@ class JointPermissionBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create & Save entity jointPermissions for many entities and roles.
|
* Create & Save collapsed entity permissions.
|
||||||
*
|
*
|
||||||
* @param Entity[] $originalEntities
|
* @param Entity[] $originalEntities
|
||||||
* @param Role[] $roles
|
|
||||||
*/
|
*/
|
||||||
protected function createManyJointPermissions(array $originalEntities, array $roles)
|
protected function generateCollapsedPermissions(array $originalEntities)
|
||||||
{
|
{
|
||||||
$entities = $this->entitiesToSimpleEntities($originalEntities);
|
$entities = $this->entitiesToSimpleEntities($originalEntities);
|
||||||
$this->readyEntityCache($entities);
|
|
||||||
$jointPermissions = [];
|
$jointPermissions = [];
|
||||||
$jointUserPermissions = [];
|
|
||||||
|
|
||||||
// Fetch related entity permissions
|
// Fetch related entity permissions
|
||||||
$permissions = $this->getEntityPermissionsForEntities($entities);
|
$permissions = $this->getEntityPermissionsForEntities($entities);
|
||||||
|
|
||||||
// Create a mapping of explicit entity permissions
|
// Create a mapping of explicit entity permissions
|
||||||
$permissionMap = [];
|
$permissionMap = new EntityPermissionMap($permissions);
|
||||||
$controlledUserIds = [];
|
|
||||||
foreach ($permissions as $permission) {
|
|
||||||
$type = $permission->role_id ? 'role' : ($permission->user_id ? 'user' : 'fallback');
|
|
||||||
$id = $permission->role_id ?? $permission->user_id ?? '0';
|
|
||||||
$key = $permission->entity_type . ':' . $permission->entity_id . ':' . $type . ':' . $id;
|
|
||||||
if ($type === 'user') {
|
|
||||||
$controlledUserIds[$id] = true;
|
|
||||||
}
|
|
||||||
$permissionMap[$key] = $permission->view;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a mapping of role permissions
|
|
||||||
$rolePermissionMap = [];
|
|
||||||
foreach ($roles as $role) {
|
|
||||||
foreach ($role->permissions as $permission) {
|
|
||||||
$rolePermissionMap[$role->getRawAttribute('id') . ':' . $permission->getRawAttribute('name')] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Joint Permission Data
|
// Create Joint Permission Data
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
foreach ($roles as $role) {
|
array_push($jointPermissions, ...$this->createCollapsedPermissionData($entity, $permissionMap));
|
||||||
$jointPermissions[] = $this->createJointPermissionData(
|
|
||||||
$entity,
|
|
||||||
$role->getRawAttribute('id'),
|
|
||||||
$permissionMap,
|
|
||||||
$rolePermissionMap,
|
|
||||||
$role->system_name === 'admin'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
foreach ($controlledUserIds as $userId => $exists) {
|
|
||||||
$userPermitted = $this->getUserPermissionOverrideStatus($entity, $userId, $permissionMap);
|
|
||||||
if ($userPermitted !== null) {
|
|
||||||
$jointUserPermissions[] = $this->createJointUserPermissionDataArray($entity, $userId, $userPermitted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($jointPermissions) {
|
DB::transaction(function () use ($jointPermissions) {
|
||||||
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
||||||
DB::table('joint_permissions')->insert($jointPermissionChunk);
|
DB::table('entity_permissions_collapsed')->insert($jointPermissionChunk);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($jointUserPermissions) {
|
/**
|
||||||
foreach (array_chunk($jointUserPermissions, 1000) as $jointUserPermissionsChunk) {
|
* Create collapsed permission data for the given entity using the given permission map.
|
||||||
DB::table('joint_user_permissions')->insert($jointUserPermissionsChunk);
|
*/
|
||||||
|
protected function createCollapsedPermissionData(SimpleEntityData $entity, EntityPermissionMap $permissionMap): array
|
||||||
|
{
|
||||||
|
$chain = [
|
||||||
|
$entity->type . ':' . $entity->id,
|
||||||
|
$entity->chapter_id ? null : ('chapter:' . $entity->chapter_id),
|
||||||
|
$entity->book_id ? null : ('book:' . $entity->book_id),
|
||||||
|
];
|
||||||
|
|
||||||
|
$permissionData = [];
|
||||||
|
$overridesApplied = [];
|
||||||
|
|
||||||
|
foreach ($chain as $entityTypeId) {
|
||||||
|
if ($entityTypeId === null) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
$permissions = $permissionMap->getForEntity($entityTypeId);
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
$related = $permission->getAssignedType() . ':' . $permission->getAssignedTypeId();
|
||||||
|
if (!isset($overridesApplied[$related])) {
|
||||||
|
$permissionData[] = [
|
||||||
|
'role_id' => $permission->role_id,
|
||||||
|
'user_id' => $permission->user_id,
|
||||||
|
'view' => $permission->view,
|
||||||
|
'entity_type' => $entity->type,
|
||||||
|
'entity_id' => $entity->id,
|
||||||
|
];
|
||||||
|
$overridesApplied[$related] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $permissionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,136 +274,4 @@ class JointPermissionBuilder
|
|||||||
|
|
||||||
return $permissionFetch->get()->all();
|
return $permissionFetch->get()->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create entity permission data for an entity and role
|
|
||||||
* for a particular action.
|
|
||||||
*/
|
|
||||||
protected function createJointPermissionData(SimpleEntityData $entity, int $roleId, array $permissionMap, array $rolePermissionMap, bool $isAdminRole): array
|
|
||||||
{
|
|
||||||
$permissionPrefix = $entity->type . '-view';
|
|
||||||
$roleHasPermission = isset($rolePermissionMap[$roleId . ':' . $permissionPrefix . '-all']);
|
|
||||||
$roleHasPermissionOwn = isset($rolePermissionMap[$roleId . ':' . $permissionPrefix . '-own']);
|
|
||||||
|
|
||||||
if ($isAdminRole) {
|
|
||||||
return $this->createJointPermissionDataArray($entity, $roleId, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->entityPermissionsActiveForRole($permissionMap, $entity, $roleId)) {
|
|
||||||
$hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $roleId);
|
|
||||||
|
|
||||||
return $this->createJointPermissionDataArray($entity, $roleId, $hasAccess, $hasAccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($entity->type === 'book' || $entity->type === 'bookshelf') {
|
|
||||||
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);
|
|
||||||
$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);
|
|
||||||
$chapterRestricted = $this->entityPermissionsActiveForRole($permissionMap, $chapter, $roleId);
|
|
||||||
$hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapterRestricted;
|
|
||||||
if ($chapterRestricted) {
|
|
||||||
$hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $chapter, $roleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createJointPermissionDataArray(
|
|
||||||
$entity,
|
|
||||||
$roleId,
|
|
||||||
($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)),
|
|
||||||
($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the status of a user-specific permission override for the given entity user combo if existing.
|
|
||||||
* This can return null where no user-specific permission overrides are applicable.
|
|
||||||
*/
|
|
||||||
protected function getUserPermissionOverrideStatus(SimpleEntityData $entity, int $userId, array $permissionMap): ?bool
|
|
||||||
{
|
|
||||||
// If direct permissions exists, return those
|
|
||||||
$directKey = $entity->type . ':' . $entity->id . ':user:' . $userId;
|
|
||||||
if (isset($permissionMap[$directKey])) {
|
|
||||||
return $permissionMap[$directKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a book or shelf, exit out since no parents to check
|
|
||||||
if ($entity->type === 'book' || $entity->type === 'bookshelf') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a chapter or page, get the parent book permission status.
|
|
||||||
// defaults to null where no permission is set.
|
|
||||||
$bookKey = 'book:' . $entity->book_id . ':user:' . $userId;
|
|
||||||
$bookPermission = $permissionMap[$bookKey] ?? null;
|
|
||||||
|
|
||||||
// If a page within a chapter, return the chapter permission if existing otherwise
|
|
||||||
// default ot the parent book permission.
|
|
||||||
if ($entity->type === 'page' && $entity->chapter_id !== 0) {
|
|
||||||
$chapterKey = 'chapter:' . $entity->chapter_id . ':user:' . $userId;
|
|
||||||
$chapterPermission = $permissionMap[$chapterKey] ?? null;
|
|
||||||
return $chapterPermission ?? $bookPermission;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the book permission status
|
|
||||||
return $bookPermission;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 . 'role:' . $roleId]) || isset($permissionMap[$keyPrefix . 'fallback:0']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for an active restriction in an entity map.
|
|
||||||
*/
|
|
||||||
protected function mapHasActiveRestriction(array $permissionMap, SimpleEntityData $entity, int $roleId): bool
|
|
||||||
{
|
|
||||||
$roleKey = $entity->type . ':' . $entity->id . ':role:' . $roleId;
|
|
||||||
$defaultKey = $entity->type . ':' . $entity->id . ':fallback:0';
|
|
||||||
|
|
||||||
return $permissionMap[$roleKey] ?? $permissionMap[$defaultKey] ?? 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, bool $permissionAll, bool $permissionOwn): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'entity_id' => $entity->id,
|
|
||||||
'entity_type' => $entity->type,
|
|
||||||
'has_permission' => $permissionAll,
|
|
||||||
'has_permission_own' => $permissionOwn,
|
|
||||||
'owned_by' => $entity->owned_by,
|
|
||||||
'role_id' => $roleId,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an array of data with the information of an JointUserPermission.
|
|
||||||
* Used to build data for bulk insertion.
|
|
||||||
*/
|
|
||||||
protected function createJointUserPermissionDataArray(SimpleEntityData $entity, int $userId, bool $hasPermission): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'entity_id' => $entity->id,
|
|
||||||
'entity_type' => $entity->type,
|
|
||||||
'has_permission' => $hasPermission,
|
|
||||||
'user_id' => $userId,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,6 @@ class PermissionsRepo
|
|||||||
|
|
||||||
$permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
|
$permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
|
||||||
$this->assignRolePermissions($role, $permissions);
|
$this->assignRolePermissions($role, $permissions);
|
||||||
$this->permissionBuilder->rebuildForRole($role);
|
|
||||||
|
|
||||||
Activity::add(ActivityType::ROLE_CREATE, $role);
|
Activity::add(ActivityType::ROLE_CREATE, $role);
|
||||||
|
|
||||||
@ -88,7 +87,6 @@ class PermissionsRepo
|
|||||||
$role->fill($roleData);
|
$role->fill($roleData);
|
||||||
$role->mfa_enforced = ($roleData['mfa_enforced'] ?? 'false') === 'true';
|
$role->mfa_enforced = ($roleData['mfa_enforced'] ?? 'false') === 'true';
|
||||||
$role->save();
|
$role->save();
|
||||||
$this->permissionBuilder->rebuildForRole($role);
|
|
||||||
|
|
||||||
Activity::add(ActivityType::ROLE_UPDATE, $role);
|
Activity::add(ActivityType::ROLE_UPDATE, $role);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
|
|||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
class CreateJointUserPermissionsTable extends Migration
|
class CreateCollapsedRolePermissionsTable extends Migration
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Run the migrations.
|
* Run the migrations.
|
||||||
@ -13,13 +13,15 @@ class CreateJointUserPermissionsTable extends Migration
|
|||||||
*/
|
*/
|
||||||
public function up()
|
public function up()
|
||||||
{
|
{
|
||||||
Schema::create('joint_user_permissions', function (Blueprint $table) {
|
Schema::create('entity_permissions_collapsed', function (Blueprint $table) {
|
||||||
$table->unsignedInteger('user_id');
|
$table->id();
|
||||||
|
$table->unsignedInteger('role_id')->nullable();
|
||||||
|
$table->unsignedInteger('user_id')->nullable();
|
||||||
$table->string('entity_type');
|
$table->string('entity_type');
|
||||||
$table->unsignedInteger('entity_id');
|
$table->unsignedInteger('entity_id');
|
||||||
$table->boolean('has_permission')->index();
|
$table->boolean('view')->index();
|
||||||
|
|
||||||
$table->primary(['user_id', 'entity_type', 'entity_id']);
|
$table->index(['entity_type', 'entity_id']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +32,6 @@ class CreateJointUserPermissionsTable extends Migration
|
|||||||
*/
|
*/
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
Schema::dropIfExists('joint_user_permissions');
|
Schema::dropIfExists('entity_permissions_collapsed');
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -34,8 +34,6 @@ class PermissionsProvider
|
|||||||
*/
|
*/
|
||||||
public function removeUserRolePermissions(User $user, array $permissions): void
|
public function removeUserRolePermissions(User $user, array $permissions): void
|
||||||
{
|
{
|
||||||
$permissionBuilder = app()->make(JointPermissionBuilder::class);
|
|
||||||
|
|
||||||
foreach ($permissions as $permissionName) {
|
foreach ($permissions as $permissionName) {
|
||||||
/** @var RolePermission $permission */
|
/** @var RolePermission $permission */
|
||||||
$permission = RolePermission::query()
|
$permission = RolePermission::query()
|
||||||
@ -49,7 +47,6 @@ class PermissionsProvider
|
|||||||
/** @var Role $role */
|
/** @var Role $role */
|
||||||
foreach ($roles as $role) {
|
foreach ($roles as $role) {
|
||||||
$role->detachPermission($permission);
|
$role->detachPermission($permission);
|
||||||
$permissionBuilder->rebuildForRole($role);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->clearPermissionCache();
|
$user->clearPermissionCache();
|
||||||
|
@ -89,7 +89,6 @@ class PublicActionTest extends TestCase
|
|||||||
foreach (RolePermission::all() as $perm) {
|
foreach (RolePermission::all() as $perm) {
|
||||||
$publicRole->attachPermission($perm);
|
$publicRole->attachPermission($perm);
|
||||||
}
|
}
|
||||||
$this->app->make(JointPermissionBuilder::class)->rebuildForRole($publicRole);
|
|
||||||
user()->clearPermissionCache();
|
user()->clearPermissionCache();
|
||||||
|
|
||||||
$chapter = $this->entities->chapter();
|
$chapter = $this->entities->chapter();
|
||||||
|
Reference in New Issue
Block a user