Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panel\Field::role() allow passing $roles #6654

Merged
merged 12 commits into from
Oct 14, 2024
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
Loading