mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 06:14:39 +08:00
Added hidden public role to fit with new permissions system
This commit is contained in:
parent
59367b3417
commit
05666efda9
|
@ -63,11 +63,13 @@ class PermissionController extends Controller
|
|||
* Show the form for editing a user role.
|
||||
* @param $id
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @throws PermissionsException
|
||||
*/
|
||||
public function editRole($id)
|
||||
{
|
||||
$this->checkPermission('user-roles-manage');
|
||||
$role = $this->permissionsRepo->getRoleById($id);
|
||||
if ($role->hidden) throw new PermissionsException('This role cannot be edited');
|
||||
return view('settings/roles/edit', ['role' => $role]);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ class UserController extends Controller
|
|||
{
|
||||
$this->checkPermission('users-manage');
|
||||
$authMethod = config('auth.method');
|
||||
return view('users/create', ['authMethod' => $authMethod]);
|
||||
$roles = $this->userRepo->getAssignableRoles();
|
||||
return view('users/create', ['authMethod' => $authMethod, 'roles' => $roles]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,7 +118,8 @@ class UserController extends Controller
|
|||
$user = $this->user->findOrFail($id);
|
||||
$activeSocialDrivers = $socialAuthService->getActiveDrivers();
|
||||
$this->setPageTitle('User Profile');
|
||||
return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod]);
|
||||
$roles = $this->userRepo->getAssignableRoles();
|
||||
return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,8 @@ class PermissionsRepo
|
|||
protected $role;
|
||||
protected $restrictionService;
|
||||
|
||||
protected $systemRoles = ['admin', 'public'];
|
||||
|
||||
/**
|
||||
* PermissionsRepo constructor.
|
||||
* @param Permission $permission
|
||||
|
@ -33,7 +35,7 @@ class PermissionsRepo
|
|||
*/
|
||||
public function getAllRoles()
|
||||
{
|
||||
return $this->role->all();
|
||||
return $this->role->where('hidden', '=', false)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +45,7 @@ class PermissionsRepo
|
|||
*/
|
||||
public function getAllRolesExcept(Role $role)
|
||||
{
|
||||
return $this->role->where('id', '!=', $role->id)->get();
|
||||
return $this->role->where('id', '!=', $role->id)->where('hidden', '=', false)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,10 +84,14 @@ class PermissionsRepo
|
|||
* Ensure Admin role always has all permissions.
|
||||
* @param $roleId
|
||||
* @param $roleData
|
||||
* @throws PermissionsException
|
||||
*/
|
||||
public function updateRole($roleId, $roleData)
|
||||
{
|
||||
$role = $this->role->findOrFail($roleId);
|
||||
|
||||
if ($role->hidden) throw new PermissionsException("Cannot update a hidden role");
|
||||
|
||||
$permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
|
||||
$this->assignRolePermissions($role, $permissions);
|
||||
|
||||
|
@ -128,8 +134,8 @@ class PermissionsRepo
|
|||
$role = $this->role->findOrFail($roleId);
|
||||
|
||||
// Prevent deleting admin role or default registration role.
|
||||
if ($role->name === 'admin') {
|
||||
throw new PermissionsException('The admin role cannot be deleted');
|
||||
if ($role->system_name && in_array($role->system_name, $this->systemRoles)) {
|
||||
throw new PermissionsException('This role is a system role and cannot be deleted');
|
||||
} else if ($role->id == setting('registration-role')) {
|
||||
throw new PermissionsException('This role cannot be deleted while set as the default registration role.');
|
||||
}
|
||||
|
|
|
@ -168,6 +168,15 @@ class UserRepo
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the roles in the system that are assignable to a user.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAssignableRoles()
|
||||
{
|
||||
return $this->role->visible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the roles which can be given restricted access to
|
||||
* other entities in the system.
|
||||
|
@ -175,7 +184,7 @@ class UserRepo
|
|||
*/
|
||||
public function getRestrictableRoles()
|
||||
{
|
||||
return $this->role->where('name', '!=', 'admin')->get();
|
||||
return $this->role->where('hidden', '=', false)->where('system_name', '=', '')->get();
|
||||
}
|
||||
|
||||
}
|
20
app/Role.php
20
app/Role.php
|
@ -72,4 +72,24 @@ class Role extends Model
|
|||
{
|
||||
return static::where('name', '=', $roleName)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the role object for the specified system role.
|
||||
* @param $roleName
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getSystemRole($roleName)
|
||||
{
|
||||
return static::where('system_name', '=', $roleName)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* GEt all visible roles
|
||||
* @return mixed
|
||||
*/
|
||||
public static function visible()
|
||||
{
|
||||
return static::where('hidden', '=', false)->orderBy('name')->get();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,9 +35,10 @@ class RestrictionService
|
|||
public function __construct(EntityPermission $entityPermission, Book $book, Chapter $chapter, Page $page, Role $role)
|
||||
{
|
||||
$this->currentUser = auth()->user();
|
||||
if ($this->currentUser === null) $this->currentUser = new User(['id' => 0]);
|
||||
$this->userRoles = $this->currentUser ? $this->currentUser->roles->pluck('id') : [];
|
||||
$this->isAdmin = $this->currentUser ? $this->currentUser->hasRole('admin') : false;
|
||||
$userSet = $this->currentUser !== null;
|
||||
$this->userRoles = false;
|
||||
$this->isAdmin = $userSet ? $this->currentUser->hasRole('admin') : false;
|
||||
if (!$userSet) $this->currentUser = new User();
|
||||
|
||||
$this->entityPermission = $entityPermission;
|
||||
$this->role = $role;
|
||||
|
@ -46,6 +47,28 @@ class RestrictionService
|
|||
$this->page = $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the roles for the current user;
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function getRoles()
|
||||
{
|
||||
if ($this->userRoles !== false) return $this->userRoles;
|
||||
|
||||
$roles = [];
|
||||
|
||||
if (auth()->guest()) {
|
||||
$roles[] = $this->role->getSystemRole('public')->id;
|
||||
return $roles;
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->currentUser->roles as $role) {
|
||||
$roles[] = $role->id;
|
||||
}
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-generate all entity permission from scratch.
|
||||
*/
|
||||
|
@ -346,7 +369,7 @@ class RestrictionService
|
|||
{
|
||||
return $query->where(function ($parentQuery) {
|
||||
$parentQuery->whereHas('permissions', function ($permissionQuery) {
|
||||
$permissionQuery->whereIn('role_id', $this->userRoles)
|
||||
$permissionQuery->whereIn('role_id', $this->getRoles())
|
||||
->where('action', '=', $this->currentAction)
|
||||
->where(function ($query) {
|
||||
$query->where('has_permission', '=', true)
|
||||
|
@ -428,7 +451,7 @@ class RestrictionService
|
|||
->whereRaw('entity_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
|
||||
->whereRaw('entity_permissions.entity_type=' . $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'])
|
||||
->where('action', '=', $this->currentAction)
|
||||
->whereIn('role_id', $this->userRoles)
|
||||
->whereIn('role_id', $this->getRoles())
|
||||
->where(function ($query) {
|
||||
$query->where('has_permission', '=', true)->orWhere(function ($query) {
|
||||
$query->where('has_permission_own', '=', true)
|
||||
|
@ -460,7 +483,7 @@ class RestrictionService
|
|||
->whereRaw('entity_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
|
||||
->where('entity_type', '=', 'Bookstack\\Page')
|
||||
->where('action', '=', $this->currentAction)
|
||||
->whereIn('role_id', $this->userRoles)
|
||||
->whereIn('role_id', $this->getRoles())
|
||||
->where(function ($query) {
|
||||
$query->where('has_permission', '=', true)->orWhere(function ($query) {
|
||||
$query->where('has_permission_own', '=', true)
|
||||
|
|
|
@ -39,7 +39,6 @@ if (!function_exists('versioned_asset')) {
|
|||
*/
|
||||
function userCan($permission, \BookStack\Ownable $ownable = null)
|
||||
{
|
||||
if (!auth()->check()) return false;
|
||||
if ($ownable === null) {
|
||||
return auth()->user() && auth()->user()->can($permission);
|
||||
}
|
||||
|
|
|
@ -21,12 +21,53 @@ class CreateEntityPermissionsTable extends Migration
|
|||
$table->boolean('has_permission')->default(false);
|
||||
$table->boolean('has_permission_own')->default(false);
|
||||
$table->integer('created_by');
|
||||
// Create indexes
|
||||
$table->index(['entity_id', 'entity_type']);
|
||||
$table->index('has_permission');
|
||||
$table->index('has_permission_own');
|
||||
$table->index('role_id');
|
||||
$table->index('action');
|
||||
$table->index('created_by');
|
||||
});
|
||||
|
||||
Schema::table('roles', function (Blueprint $table) {
|
||||
$table->string('system_name');
|
||||
$table->boolean('hidden')->default(false);
|
||||
$table->index('hidden');
|
||||
$table->index('system_name');
|
||||
});
|
||||
|
||||
// Create the new public role
|
||||
$publicRole = new \BookStack\Role();
|
||||
$publicRole->name = 'public';
|
||||
$publicRole->display_name = 'Public';
|
||||
$publicRole->description = 'The role given to public visitors if allowed';
|
||||
$publicRole->system_name = 'public';
|
||||
$publicRole->hidden = true;
|
||||
// Ensure unique name
|
||||
while (\BookStack\Role::getRole($publicRole->name) !== null) {
|
||||
$publicRole->name = $publicRole->name . str_random(2);
|
||||
}
|
||||
$publicRole->save();
|
||||
|
||||
// Add new view permissions to public role
|
||||
$entities = ['Book', 'Page', 'Chapter'];
|
||||
$ops = ['View All', 'View Own'];
|
||||
foreach ($entities as $entity) {
|
||||
foreach ($ops as $op) {
|
||||
$name = strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op));
|
||||
$permission = \BookStack\Permission::getByName($name);
|
||||
// Assign view permissions to public
|
||||
$publicRole->attachPermission($permission);
|
||||
}
|
||||
}
|
||||
|
||||
// Update admin role with system name
|
||||
$admin = \BookStack\Role::getRole('admin');
|
||||
$admin->system_name = 'admin';
|
||||
$admin->save();
|
||||
|
||||
// Generate the new entity permissions
|
||||
$restrictionService = app(\BookStack\Services\RestrictionService::class);
|
||||
$restrictionService->buildEntityPermissions();
|
||||
}
|
||||
|
@ -39,5 +80,13 @@ class CreateEntityPermissionsTable extends Migration
|
|||
public function down()
|
||||
{
|
||||
Schema::drop('entity_permissions');
|
||||
|
||||
// Delete the public role
|
||||
$public = \BookStack\Role::getSystemRole('public');
|
||||
$public->delete();
|
||||
|
||||
Schema::table('roles', function (Blueprint $table) {
|
||||
$table->dropColumn('system_name');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,9 +49,15 @@
|
|||
<hr>
|
||||
<p class="text-muted">No pages are currently in this chapter.</p>
|
||||
<p>
|
||||
<a href="{{$chapter->getUrl() . '/create-page'}}" class="text-page"><i class="zmdi zmdi-file-text"></i>Create a new page</a>
|
||||
<em class="text-muted">-or-</em>
|
||||
<a href="{{$book->getUrl() . '/sort'}}" class="text-book"><i class="zmdi zmdi-book"></i>Sort the current book</a>
|
||||
@if(userCan('page-create', $chapter))
|
||||
<a href="{{$chapter->getUrl() . '/create-page'}}" class="text-page"><i class="zmdi zmdi-file-text"></i>Create a new page</a>
|
||||
@endif
|
||||
@if(userCan('page-create', $chapter) && userCan('book-update', $book))
|
||||
<em class="text-muted">-or-</em>
|
||||
@endif
|
||||
@if(userCan('book-update', $book))
|
||||
<a href="{{$book->getUrl() . '/sort'}}" class="text-book"><i class="zmdi zmdi-book"></i>Sort the current book</a>
|
||||
@endif
|
||||
</p>
|
||||
<hr>
|
||||
@endif
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
<div class="form-group">
|
||||
<label for="setting-registration-role">Default user role after registration</label>
|
||||
<select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
|
||||
@foreach(\BookStack\Role::all() as $role)
|
||||
<option value="{{$role->id}}"
|
||||
@foreach(\BookStack\Role::visible() as $role)
|
||||
<option value="{{$role->id}}" data-role-name="{{ $role->name }}"
|
||||
@if(setting('registration-role', \BookStack\Role::first()->id) == $role->id) selected @endif
|
||||
>
|
||||
{{ $role->display_name }}
|
||||
|
|
|
@ -31,11 +31,11 @@
|
|||
</p>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Create</th>
|
||||
<th>View</th>
|
||||
<th>Edit</th>
|
||||
<th>Delete</th>
|
||||
<th width="20%"></th>
|
||||
<th width="20%">Create</th>
|
||||
<th width="20%">View</th>
|
||||
<th width="20%">Edit</th>
|
||||
<th width="20%">Delete</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Books</td>
|
||||
|
@ -96,6 +96,7 @@
|
|||
<tr>
|
||||
<td>Images</td>
|
||||
<td>@include('settings/roles/checkbox', ['permission' => 'image-create-all'])</td>
|
||||
<td style="line-height:1.2;"><small class="faded">Controlled by the asset they are uploaded to</small></td>
|
||||
<td>
|
||||
<label>@include('settings/roles/checkbox', ['permission' => 'image-update-own']) Own</label>
|
||||
<label>@include('settings/roles/checkbox', ['permission' => 'image-update-all']) All</label>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
@if(userCan('users-manage'))
|
||||
<div class="form-group">
|
||||
<label for="role">User Role</label>
|
||||
@include('form/role-checkboxes', ['name' => 'roles', 'roles' => \BookStack\Role::all()])
|
||||
@include('form/role-checkboxes', ['name' => 'roles', 'roles' => $roles])
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
@if(userCan('users-manage'))
|
||||
<div class="form-group">
|
||||
<label for="role">User Role</label>
|
||||
@include('form/role-checkboxes', ['name' => 'roles', 'roles' => \BookStack\Role::all()])
|
||||
@include('form/role-checkboxes', ['name' => 'roles', 'roles' => $roles])
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
|
|
@ -544,4 +544,27 @@ class RolesTest extends TestCase
|
|||
->dontSeeInElement('.book-content', $otherPage->name);
|
||||
}
|
||||
|
||||
public function test_public_role_not_visible_in_user_edit_screen()
|
||||
{
|
||||
$user = \BookStack\User::first();
|
||||
$this->asAdmin()->visit('/settings/users/' . $user->id)
|
||||
->seeElement('#roles-admin')
|
||||
->dontSeeElement('#roles-public');
|
||||
}
|
||||
|
||||
public function test_public_role_not_visible_in_role_listing()
|
||||
{
|
||||
$this->asAdmin()->visit('/settings/roles')
|
||||
->see('Admin')
|
||||
->dontSee('Public');
|
||||
}
|
||||
|
||||
public function test_public_role_not_visible_in_default_role_setting()
|
||||
{
|
||||
$this->asAdmin()->visit('/settings')
|
||||
->seeElement('[data-role-name="admin"]')
|
||||
->dontSeeElement('[data-role-name="public"]');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user