Skip to content

Commit aee0e16

Browse files
committed
Started code update for new entity permission format
1 parent 1d3dbd6 commit aee0e16

9 files changed

Lines changed: 70 additions & 43 deletions

File tree

app/Auth/Permissions/EntityPermission.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,29 @@
33
namespace BookStack\Auth\Permissions;
44

55
use BookStack\Model;
6+
use Illuminate\Database\Eloquent\Relations\MorphTo;
67

8+
/**
9+
* @property int $id
10+
* @property int $role_id
11+
* @property int $entity_id
12+
* @property string $entity_type
13+
* @property boolean $view
14+
* @property boolean $create
15+
* @property boolean $update
16+
* @property boolean $delete
17+
*/
718
class EntityPermission extends Model
819
{
9-
protected $fillable = ['role_id', 'action'];
20+
public const PERMISSIONS = ['view', 'create', 'update', 'delete'];
21+
22+
protected $fillable = ['role_id', 'view', 'create', 'update', 'delete'];
1023
public $timestamps = false;
1124

1225
/**
13-
* Get all this restriction's attached entity.
14-
*
15-
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
26+
* Get this restriction's attached entity.
1627
*/
17-
public function restrictable()
28+
public function restrictable(): MorphTo
1829
{
1930
return $this->morphTo('restrictable');
2031
}

app/Auth/Permissions/JointPermissionBuilder.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,13 @@ protected function createManyJointPermissions(array $originalEntities, array $ro
250250
$permissions = $this->getEntityPermissionsForEntities($entities);
251251

252252
// Create a mapping of explicit entity permissions
253+
// TODO - Handle new format, Now getting all defined entity permissions
254+
// from the above call, Need to handle entries with none, and the 'Other Roles' (role_id=0)
255+
// fallback option.
253256
$permissionMap = [];
254257
foreach ($permissions as $permission) {
255-
$key = $permission->restrictable_type . ':' . $permission->restrictable_id . ':' . $permission->role_id;
256-
$isRestricted = $entityRestrictedMap[$permission->restrictable_type . ':' . $permission->restrictable_id];
258+
$key = $permission->entity_type . ':' . $permission->entity_id . ':' . $permission->role_id;
259+
$isRestricted = $entityRestrictedMap[$permission->entity_type . ':' . $permission->entity_id];
257260
$permissionMap[$key] = $isRestricted;
258261
}
259262

@@ -319,11 +322,10 @@ protected function getEntityPermissionsForEntities(array $entities): array
319322
{
320323
$idsByType = $this->entitiesToTypeIdMap($entities);
321324
$permissionFetch = EntityPermission::query()
322-
->where('action', '=', 'view')
323325
->where(function (Builder $query) use ($idsByType) {
324326
foreach ($idsByType as $type => $ids) {
325327
$query->orWhere(function (Builder $query) use ($type, $ids) {
326-
$query->where('restrictable_type', '=', $type)->whereIn('restrictable_id', $ids);
328+
$query->where('entity_type', '=', $type)->whereIn('entity_id', $ids);
327329
});
328330
}
329331
});

app/Auth/Permissions/PermissionApplicator.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public function checkOwnableUserAccess(Model $ownable, string $permission): bool
5959
*/
6060
protected function hasEntityPermission(Entity $entity, array $userRoleIds, string $action): ?bool
6161
{
62+
$this->ensureValidEntityAction($action);
63+
6264
$adminRoleId = Role::getSystemRole('admin')->id;
6365
if (in_array($adminRoleId, $userRoleIds)) {
6466
return true;
@@ -81,7 +83,7 @@ protected function hasEntityPermission(Entity $entity, array $userRoleIds, strin
8183
if ($currentEntity->restricted) {
8284
return $currentEntity->permissions()
8385
->whereIn('role_id', $userRoleIds)
84-
->where('action', '=', $action)
86+
->where($action, '=', true)
8587
->count() > 0;
8688
}
8789
}
@@ -95,18 +97,16 @@ protected function hasEntityPermission(Entity $entity, array $userRoleIds, strin
9597
*/
9698
public function checkUserHasEntityPermissionOnAny(string $action, string $entityClass = ''): bool
9799
{
98-
if (strpos($action, '-') !== false) {
99-
throw new InvalidArgumentException('Action should be a simple entity permission action, not a role permission');
100-
}
100+
$this->ensureValidEntityAction($action);
101101

102102
$permissionQuery = EntityPermission::query()
103-
->where('action', '=', $action)
103+
->where($action, '=', true)
104104
->whereIn('role_id', $this->getCurrentUserRoleIds());
105105

106106
if (!empty($entityClass)) {
107107
/** @var Entity $entityInstance */
108108
$entityInstance = app()->make($entityClass);
109-
$permissionQuery = $permissionQuery->where('restrictable_type', '=', $entityInstance->getMorphClass());
109+
$permissionQuery = $permissionQuery->where('entity_type', '=', $entityInstance->getMorphClass());
110110
}
111111

112112
$hasPermission = $permissionQuery->count() > 0;
@@ -255,4 +255,16 @@ protected function getCurrentUserRoleIds(): array
255255

256256
return $this->currentUser()->roles->pluck('id')->values()->all();
257257
}
258+
259+
/**
260+
* Ensure the given action is a valid and expected entity action.
261+
* Throws an exception if invalid otherwise does nothing.
262+
* @throws InvalidArgumentException
263+
*/
264+
protected function ensureValidEntityAction(string $action): void
265+
{
266+
if (!in_array($action, EntityPermission::PERMISSIONS)) {
267+
throw new InvalidArgumentException('Action should be a simple entity permission action, not a role permission');
268+
}
269+
}
258270
}

app/Entities/Models/Entity.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public function searchTerms(): MorphMany
176176
*/
177177
public function permissions(): MorphMany
178178
{
179-
return $this->morphMany(EntityPermission::class, 'restrictable');
179+
return $this->morphMany(EntityPermission::class, 'entity');
180180
}
181181

182182
/**
@@ -186,7 +186,7 @@ public function hasRestriction(int $role_id, string $action): bool
186186
{
187187
return $this->permissions()
188188
->where('role_id', '=', $role_id)
189-
->where('action', '=', $action)
189+
->where($action, '=', true)
190190
->count() > 0;
191191
}
192192

app/Entities/Repos/BookshelfRepo.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ protected function updateBooks(Bookshelf $shelf, array $bookIds)
139139
*/
140140
public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int
141141
{
142-
$shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray();
142+
$shelfPermissions = $shelf->permissions()->get(['role_id', 'view', 'create', 'update', 'delete'])->toArray();
143143
$shelfBooks = $shelf->books()->get(['id', 'restricted', 'owned_by']);
144144
$updatedBookCount = 0;
145145

app/Entities/Tools/Cloner.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public function entityToInputData(Entity $entity): array
123123
public function copyEntityPermissions(Entity $sourceEntity, Entity $targetEntity): void
124124
{
125125
$targetEntity->restricted = $sourceEntity->restricted;
126-
$permissions = $sourceEntity->permissions()->get(['role_id', 'action'])->toArray();
126+
$permissions = $sourceEntity->permissions()->get(['role_id', 'view', 'create', 'update', 'delete'])->toArray();
127127
$targetEntity->permissions()->delete();
128128
$targetEntity->permissions()->createMany($permissions);
129129
$targetEntity->rebuildPermissions();

app/Entities/Tools/PermissionsUpdater.php

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace BookStack\Entities\Tools;
44

55
use BookStack\Actions\ActivityType;
6+
use BookStack\Auth\Permissions\EntityPermission;
67
use BookStack\Auth\User;
78
use BookStack\Entities\Models\Entity;
89
use BookStack\Facades\Activity;
@@ -16,11 +17,9 @@ class PermissionsUpdater
1617
*/
1718
public function updateFromPermissionsForm(Entity $entity, Request $request)
1819
{
19-
$restricted = $request->get('restricted') === 'true';
20-
$permissions = $request->get('restrictions', null);
20+
$permissions = $request->get('permissions', null);
2121
$ownerId = $request->get('owned_by', null);
2222

23-
$entity->restricted = $restricted;
2423
$entity->permissions()->delete();
2524

2625
if (!is_null($permissions)) {
@@ -52,18 +51,20 @@ protected function updateOwnerFromId(Entity $entity, int $newOwnerId)
5251
}
5352

5453
/**
55-
* Format permissions provided from a permission form to be
56-
* EntityPermission data.
54+
* Format permissions provided from a permission form to be EntityPermission data.
5755
*/
58-
protected function formatPermissionsFromRequestToEntityPermissions(array $permissions): Collection
56+
protected function formatPermissionsFromRequestToEntityPermissions(array $permissions): array
5957
{
60-
return collect($permissions)->flatMap(function ($restrictions, $roleId) {
61-
return collect($restrictions)->keys()->map(function ($action) use ($roleId) {
62-
return [
63-
'role_id' => $roleId,
64-
'action' => strtolower($action),
65-
];
66-
});
67-
});
58+
$formatted = [];
59+
60+
foreach ($permissions as $roleId => $info) {
61+
$entityPermissionData = ['role_id' => $roleId];
62+
foreach (EntityPermission::PERMISSIONS as $permission) {
63+
$entityPermissionData[$permission] = (($info[$permission] ?? false) === "true");
64+
}
65+
$formatted[] = $entityPermissionData;
66+
}
67+
68+
return $formatted;
6869
}
6970
}

resources/views/form/entity-permissions-row.blade.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,20 @@ class="ml-auto flex-none text-small text-primary text-button hover-underline con
2828
</div>
2929
@endif
3030
<div class="flex-container-row justify-space-between gap-x-xl wrap items-center">
31+
<input type="hidden" name="permissions[{{ $role->id }}][active]" value="true">
3132
<div class="px-l">
32-
@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view', 'disabled' => $inheriting])
33+
@include('form.restriction-checkbox', ['name'=>'permissions', 'label' => trans('common.view'), 'action' => 'view', 'disabled' => $inheriting])
3334
</div>
3435
<div class="px-l">
3536
@if(!$model instanceof \BookStack\Entities\Models\Page)
36-
@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create', 'disabled' => $inheriting])
37+
@include('form.restriction-checkbox', ['name'=>'permissions', 'label' => trans('common.create'), 'action' => 'create', 'disabled' => $inheriting])
3738
@endif
3839
</div>
3940
<div class="px-l">
40-
@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update', 'disabled' => $inheriting])
41+
@include('form.restriction-checkbox', ['name'=>'permissions', 'label' => trans('common.update'), 'action' => 'update', 'disabled' => $inheriting])
4142
</div>
4243
<div class="px-l">
43-
@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete', 'disabled' => $inheriting])
44+
@include('form.restriction-checkbox', ['name'=>'permissions', 'label' => trans('common.delete'), 'action' => 'delete', 'disabled' => $inheriting])
4445
</div>
4546
</div>
4647
</div>

tests/Helpers/EntityProvider.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Tests\Helpers;
44

5+
use BookStack\Auth\Permissions\EntityPermission;
56
use BookStack\Auth\Role;
67
use BookStack\Auth\User;
78
use BookStack\Entities\Models\Book;
@@ -207,13 +208,12 @@ public function setPermissions(Entity $entity, array $actions = [], array $roles
207208
$entity->permissions()->delete();
208209

209210
$permissions = [];
210-
foreach ($actions as $action) {
211-
foreach ($roles as $role) {
212-
$permissions[] = [
213-
'role_id' => $role->id,
214-
'action' => strtolower($action),
215-
];
211+
foreach ($roles as $role) {
212+
$permission = ['role_id' => $role->id];
213+
foreach (EntityPermission::PERMISSIONS as $possibleAction) {
214+
$permission[$possibleAction] = in_array($possibleAction, $actions);
216215
}
216+
$permissions[] = $permission;
217217
}
218218

219219
$entity->permissions()->createMany($permissions);

0 commit comments

Comments
 (0)