Skip to content

Commit

Permalink
Merge pull request #6654 from getkirby/enhancement/panel-field-role
Browse files Browse the repository at this point in the history
`Panel\Field::role()` allow passing `$roles`
  • Loading branch information
bastianallgeier authored Oct 14, 2024
2 parents 927d925 + be0b774 commit f5fee06
Show file tree
Hide file tree
Showing 13 changed files with 231 additions and 95 deletions.
26 changes: 17 additions & 9 deletions config/areas/users/dialogs.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
'pattern' => 'users/create',
'load' => function () {
$kirby = App::instance();
$roles = $kirby->roles()->canBeCreated();

// get default value for role
if ($role = $kirby->request()->get('role')) {
$role = $kirby->roles()->find($role)?->id();
$role = $roles->find($role)?->id();
}

// get role field definition, incl. available role options
$roles = Field::role(
roles: $roles,
props: ['required' => true]
);

return [
'component' => 'k-form-dialog',
'props' => [
Expand All @@ -39,17 +46,15 @@
'translation' => Field::translation([
'required' => true
]),
'role' => Field::role([
'required' => true
])
'role' => $roles
],
'submitButton' => I18n::translate('create'),
'value' => [
'name' => '',
'email' => '',
'password' => '',
'translation' => $kirby->panelLanguage(),
'role' => $role ?? $kirby->user()->role()->name()
'role' => $role ?? $roles['options'][0]['value'] ?? null
]
]
];
Expand Down Expand Up @@ -228,10 +233,13 @@
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'role' => Field::role([
'label' => I18n::translate('user.changeRole.select'),
'required' => true,
])
'role' => Field::role(
roles: $user->roles(),
props: [
'label' => I18n::translate('user.changeRole.select'),
'required' => true,
]
)
],
'submitButton' => I18n::translate('user.changeRole'),
'value' => [
Expand Down
3 changes: 2 additions & 1 deletion config/areas/users/views.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
return [
'component' => 'k-users-view',
'props' => [
'role' => function () use ($kirby, $roles, $role) {
'canCreate' => $kirby->roles()->canBeCreated()->count() > 0,
'role' => function () use ($roles, $role) {
if ($role) {
return $roles[$role] ?? null;
}
Expand Down
8 changes: 7 additions & 1 deletion panel/src/components/Views/Users/UserAvatar.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<template>
<k-button :title="$t('avatar')" class="k-user-view-image" @click="open">
<k-button
:disabled="isLocked"
:title="$t('avatar')"
class="k-user-view-image"
@click="open"
>
<template v-if="model.avatar">
<k-image-frame :cover="true" :src="model.avatar" />
<k-dropdown-content
Expand Down Expand Up @@ -30,6 +35,7 @@
*/
export default {
props: {
isLocked: Boolean,
model: Object
},
methods: {
Expand Down
12 changes: 9 additions & 3 deletions panel/src/components/Views/Users/UserProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
icon: 'email',
text: `${model.email}`,
title: `${$t('email')}: ${model.email}`,
disabled: !permissions.changeEmail || isLocked,
disabled: !canChangeEmail,
click: () => $dialog(model.link + '/changeEmail')
},
{
icon: 'bolt',
text: `${model.role}`,
title: `${$t('role')}: ${model.role}`,
disabled: !permissions.changeRole || isLocked,
disabled: !canChangeRole,
click: () => $dialog(model.link + '/changeRole')
},
{
icon: 'translate',
text: `${model.language}`,
title: `${$t('language')}: ${model.language}`,
disabled: !permissions.changeLanguage || isLocked,
disabled: !canChangeLanguage,
click: () => $dialog(model.link + '/changeLanguage')
}
]"
Expand All @@ -37,8 +37,14 @@
*/
export default {
props: {
canChangeEmail: Boolean,
canChangeLanguage: Boolean,
canChangeRole: Boolean,
isLocked: Boolean,
model: Object,
/**
* @deprecated Will be remove in v5
*/
permissions: Object
}
};
Expand Down
14 changes: 12 additions & 2 deletions panel/src/components/Views/Users/UserView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</template>

<k-header
:editable="permissions.changeName && !isLocked"
:editable="canChangeName"
class="k-user-view-header"
@edit="$dialog(id + '/changeName')"
>
Expand Down Expand Up @@ -50,6 +50,10 @@
</k-header>

<k-user-profile
:can-change-email="canChangeEmail"
:can-change-language="canChangeLanguage"
:can-change-name="canChangeName"
:can-change-role="canChangeRole"
:is-locked="isLocked"
:model="model"
:permissions="permissions"
Expand All @@ -71,7 +75,13 @@
import ModelView from "../ModelView.vue";
export default {
extends: ModelView
extends: ModelView,
props: {
canChangeEmail: Boolean,
canChangeLanguage: Boolean,
canChangeName: Boolean,
canChangeRole: Boolean
}
};
</script>

Expand Down
3 changes: 2 additions & 1 deletion panel/src/components/Views/Users/UsersView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<template #buttons>
<k-button
:disabled="!$panel.permissions.users.create"
:disabled="!canCreate"
:text="$t('user.create')"
icon="add"
size="sm"
Expand All @@ -30,6 +30,7 @@
*/
export default {
props: {
canCreate: Boolean,
role: Object,
roles: Array,
search: String,
Expand Down
10 changes: 8 additions & 2 deletions src/Cms/Roles.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ class Roles extends Collection

/**
* Returns a filtered list of all
* roles that can be created by the
* roles that can be changed by the
* current user
*
* Use with `$kirby->roles()`. For retrieving
* which roles are available for a specific user,
* use `$user->roles()` without additional filters.
*
* @return $this|static
* @throws \Exception
*/
Expand All @@ -50,7 +54,9 @@ public function canBeChanged(): static
/**
* Returns a filtered list of all
* roles that can be created by the
* current user
* current user.
*
* Use with `$kirby->roles()`.
*
* @return $this|static
* @throws \Exception
Expand Down
29 changes: 8 additions & 21 deletions src/Cms/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,36 +575,23 @@ public function role(): Role

/**
* Returns all available roles for this user,
* that can be selected by the authenticated user
* that the authenticated user can change to.
*
* @param string|null $purpose User action for which the roles are used (create, change)
* For all roles the current user can create
* use `$kirby->roles()->canBeCreated()`.
*/
public function roles(string|null $purpose = null): Roles
public function roles(): Roles
{
$kirby = $this->kirby();
$roles = $kirby->roles();

// for the last admin,
// only their current role (admin) is available for changing
if ($purpose === 'change' && $this->isLastAdmin() === true) {
// a collection with just the one role of the user
// if the authenticated user doesn't have the permission to change
// the role of this user, only the current role is available
if ($this->permissions()->can('changeRole') === false) {
return $roles->filter('id', $this->role()->id());
}

// filter roles based on the user action
// as user permissions and/or options can restrict these further
$roles = match ($purpose) {
'create' => $roles->canBeCreated(),
'change' => $roles->canBeChanged(),
default => $roles
};

// exclude the admin role, if the user isn't an admin themselves
if ($kirby->user()?->isAdmin() !== true) {
$roles = $roles->filter(fn ($role) => $role->name() !== 'admin');
}

return $roles;
return $roles->canBeCreated();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Cms/UserRules.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public static function changeRole(User $user, string $role): bool
}

// prevent changing to role that is not available for user
if ($user->roles('change')->find($role) instanceof Role === false) {
if ($user->roles()->find($role) instanceof Role === false) {
throw new InvalidArgumentException([
'key' => 'user.role.invalid',
]);
Expand Down Expand Up @@ -210,7 +210,7 @@ public static function create(User $user, array $props = []): bool
// prevent creating a role that is not available for user
if (
in_array($role, [null, 'default', 'nobody'], true) === false &&
$user->kirby()->roles('create')->find($role) instanceof Role === false
$user->kirby()->roles()->canBeCreated()->find($role) instanceof Role === false
) {
throw new InvalidArgumentException([
'key' => 'user.role.invalid',
Expand Down
45 changes: 25 additions & 20 deletions src/Panel/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Kirby\Cms\File;
use Kirby\Cms\ModelWithContent;
use Kirby\Cms\Page;
use Kirby\Cms\Roles;
use Kirby\Form\Form;
use Kirby\Http\Router;
use Kirby\Toolkit\I18n;
Expand Down Expand Up @@ -191,29 +192,33 @@ public static function password(array $props = []): array
/**
* User role radio buttons
*/
public static function role(array $props = []): array
{
$kirby = App::instance();
$isAdmin = $kirby->user()?->isAdmin() ?? false;
$roles = [];

foreach ($kirby->roles() as $role) {
// exclude the admin role, if the user
// is not allowed to change role to admin
if ($role->name() === 'admin' && $isAdmin === false) {
continue;
}

$roles[] = [
'text' => $role->title(),
'info' => $role->description() ?? I18n::translate('role.description.placeholder'),
'value' => $role->name()
];
}
public static function role(
array $props = [],
Roles|null $roles = null
): array {
$kirby = App::instance();

// if no $roles where provided, fall back to all roles
$roles ??= $kirby->roles();

// exclude the admin role, if the user
// is not allowed to change role to admin
$roles = $roles->filter(
fn ($role) =>
$role->name() !== 'admin' ||
$kirby->user()?->isAdmin() === true
);

// turn roles into radio field options
$roles = $roles->values(fn ($role) => [
'text' => $role->title(),
'info' => $role->description() ?? I18n::translate('role.description.placeholder'),
'value' => $role->name()
]);

return array_merge([
'label' => I18n::translate('role'),
'type' => count($roles) <= 1 ? 'hidden' : 'radio',
'type' => count($roles) < 1 ? 'hidden' : 'radio',
'options' => $roles
], $props);
}
Expand Down
13 changes: 9 additions & 4 deletions src/Panel/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public function dropdown(array $options = []): array
'dialog' => $url . '/changeRole',
'icon' => 'bolt',
'text' => I18n::translate('user.changeRole'),
'disabled' => $this->isDisabledDropdownOption('changeRole', $options, $permissions) || $this->model->roles('change')->count() < 2
'disabled' => $this->isDisabledDropdownOption('changeRole', $options, $permissions) || $this->model->roles()->count() < 2
];

$result[] = [
Expand Down Expand Up @@ -218,14 +218,19 @@ public function prevNext(): array
*/
public function props(): array
{
$user = $this->model;
$account = $user->isLoggedIn();
$user = $this->model;
$account = $user->isLoggedIn();
$permissions = $this->options();

return array_merge(
parent::props(),
$this->prevNext(),
[
'blueprint' => $this->model->role()->name(),
'blueprint' => $this->model->role()->name(),
'canChangeEmail' => $permissions['changeEmail'],
'canChangeLanguage' => $permissions['changeLanguage'],
'canChangeName' => $permissions['changeName'],
'canChangeRole' => $this->model->roles()->count() > 1,
'model' => [
'account' => $account,
'avatar' => $user->avatar()?->url(),
Expand Down
Loading

0 comments on commit f5fee06

Please sign in to comment.